🙌

Ansibleでプライベートリポジトリをクローン・ビルドしてDockerを実行する

に公開

はじめに

プライベートGitHubリポジトリのコードを自動デプロイして実行する作業は多くの開発・運用現場で必要とされます。本記事では次の作業を自動化する手順を記録します。

  • GitHubプライベートリポジトリのクローン
  • Dockerfileからのイメージビルド
  • Dockerコンテナの実行
  • GitHub Actionsによる定期実行

※Terraform/AnsibleでのVM構築をしており、具体的なやりたいこと(アプリケーション)を別リポジトリにまとめている前提です。主にAnsible関連の内容になりますが、GitHub Actionsでの自動化の流れでの開発ですので、そちらの内容も記載しています。

環境準備

使用ツール:

  • Ansible
  • Docker
  • GitHub Actions
  • dotenvx(環境変数管理)

認証方法

GitHubプライベートリポジトリへのアクセスには2種類の認証方法があります。

認証方法 メリット デメリット
HTTPS シンプルな設定、ファイアウォール対応 認証情報管理、トークン期限切れ
SSH セキュリティ強化、鍵の管理 初期設定複雑

本記事ではSSH認証を使用します。

Ansibleプレイブックの実装

SSHキー認証の設定

まず、SSHキーを使ってGitHubプライベートリポジトリにアクセスするためのAnsibleプレイブックを作成します。
※Githubの対象リポジトリにDEPLOY KEYにSSHのPUBIC KEY登録がされていること。

---
- name: GitHubプライベートリポジトリの管理(SSH認証)
  hosts: your_target_servers
  vars:
    # 環境変数から情報を取得
    github_repo: "{{ lookup('env', 'GITHUB_REPO') }}"
    github_branch: "{{ lookup('env', 'GITHUB_BRANCH') | default('main') }}"
    repo_dest: "{{ lookup('env', 'REPO_DEST') }}"
    ssh_private_key: "{{ lookup('env', 'SSH_PRIVATE_KEY') }}"
    ssh_public_key: "{{ lookup('env', 'SSH_PUBLIC_KEY') }}"
    
    # 実行ユーザーの情報
    target_user: "{{ ansible_user | default('ubuntu') }}"
    target_user_home: "/home/{{ target_user }}"
    
    # Docker関連の変数
    docker_image_name: "{{ lookup('env', 'DOCKER_IMAGE_NAME') }}"
    docker_image_tag: "{{ lookup('env', 'DOCKER_IMAGE_TAG') | default('latest') }}"
    slack_webhook_url: "{{ lookup('env', 'SLACK_WEBHOOK_URL') }}"
  
  tasks:
    - name: 必要なパッケージをインストール
      package:
        name:
          - git
          - docker.io
        state: present
      become: yes
      
    - name: DockerサービスがRunningか確認
      service:
        name: docker
        state: started
        enabled: yes
      become: yes
      
    - name: Dockerグループが存在することを確認
      group:
        name: docker
        state: present
      become: yes
      
    - name: ユーザーをdockerグループに追加
      user:
        name: "{{ target_user }}"
        groups: docker
        append: yes
      become: yes
      
    - name: SSHディレクトリが存在することを確認
      file:
        path: "{{ target_user_home }}/.ssh"
        state: directory
        mode: '0700'
        owner: "{{ target_user }}"
        group: "{{ target_user }}"
      become: yes
      
    - name: 環境変数からSSHプライベートキーを作成
      copy:
        content: |
          {{ ssh_private_key }}
        dest: "{{ target_user_home }}/.ssh/id_github"
        mode: '0600'
        owner: "{{ target_user }}"
        group: "{{ target_user }}"
      become: yes
      when: ssh_private_key is defined and ssh_private_key != ""
      
    - name: 環境変数からSSH公開キーを作成(必要な場合)
      copy:
        content: "{{ ssh_public_key }}"
        dest: "{{ target_user_home }}/.ssh/id_github.pub"
        mode: '0644'
        owner: "{{ target_user }}"
        group: "{{ target_user }}"
      become: yes
      when: ssh_public_key is defined and ssh_public_key != ""
      
    - name: SSHの設定ファイルを作成
      blockinfile:
        path: "{{ target_user_home }}/.ssh/config"
        create: yes
        mode: '0644'
        owner: "{{ target_user }}"
        group: "{{ target_user }}"
        block: |
          Host github.com
            IdentityFile {{ target_user_home }}/.ssh/id_github
            IdentitiesOnly yes
      become: yes
      
    - name: GitHubのホスト鍵を取得
      command: ssh-keyscan -t rsa github.com
      register: github_host_key
      check_mode: no
      changed_when: false
      
    - name: known_hostsファイルを作成
      copy:
        content: "{{ github_host_key.stdout }}"
        dest: "{{ target_user_home }}/.ssh/known_hosts"
        mode: '0644'
        owner: "{{ target_user }}"
        group: "{{ target_user }}"
      become: yes
      
    - name: リポジトリのクローンディレクトリを作成
      file:
        path: "{{ repo_dest }}"
        state: directory
        mode: '0755'
        owner: "{{ target_user }}"
        group: "{{ target_user }}"
      become: yes
      
    - name: GitHubプライベートリポジトリのクローン実行
      git:
        repo: "git@github.com:{{ github_repo }}.git"
        dest: "{{ repo_dest }}"
        version: "{{ github_branch }}"
        update: yes
        accept_hostkey: yes
        key_file: "{{ target_user_home }}/.ssh/id_github"
      become: yes
      become_user: "{{ target_user }}"
      
    - name: Dockerイメージをビルド
      command:
        cmd: docker build -t {{ docker_image_name }}:{{ docker_image_tag }} .
        chdir: "{{ repo_dest }}"
      become: yes
      register: docker_build_result
      changed_when: docker_build_result.rc == 0
      
    - name: Dockerコンテナを実行
      command:
        cmd: >
          docker run --rm
          -e SLACK_WEBHOOK_URL={{ slack_webhook_url }}
          {{ docker_image_name }}:{{ docker_image_tag }}
        chdir: "{{ repo_dest }}"
      become: yes

このプレイブックは以下の処理を行います:

  1. 必要なパッケージ(GitとDocker)のインストール
  2. Dockerサービスの起動と自動起動設定
  3. SSHディレクトリの作成と設定
  4. 環境変数からSSHキーを取得し、ファイルとして保存
  5. GitHubのホスト鍵を取得して登録
  6. GitHubのプライベートリポジトリをクローン
  7. Dockerイメージのビルド
  8. 必要な環境変数を設定してDockerコンテナを実行

プレイブックの実行

Ansibleプレイブックを実行するには:

ansible-playbook -i inventory.ini playbook.yml

GitHub Actionsによる自動化

次に、GitHub Actionsを使ってこのプロセスを自動化します。以下のワークフローファイルを作成します。実行イメージにはansibleやdotenvxがインストールされているものを使用しています:

name: Deploy and Run Docker Container

on:
  schedule:
    - cron: '0 8 * * *'  # 毎日午前8時に実行
  workflow_dispatch:      # 手動実行も可能

jobs:
  deploy:
    runs-on: ubuntu-latest
    container: ghcr.io/xxx/xxx # ansibleとdotenvx使用の実行イメージ
    
    env:
      # 共通の環境変数(Variables/Secretsから取得)
      SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
      DOCKER_IMAGE_NAME: my-app
      DOCKER_IMAGE_TAG: latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
          
      - name: Setup SSH key
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts

      - name: Run Ansible playbook
        run: dotenvx run -f .env.encrypted -- ansible-playbook -i inventory.ini playbook.yml
        env:
          ANSIBLE_HOST_KEY_CHECKING: False

このワークフローは以下を行います:

  1. 毎日午前8時に自動実行、または手動で実行可能
  2. 必要なPythonパッケージとdotenvxをインストール
  3. SSHキーを設定
  4. 環境変数を表示して確認
  5. dotenvxを使用してAnsibleプレイブックを実行

GitHub ActionsでのSecret/Variables管理

GitHubリポジトリの「Settings」→「Secrets and variables」→「Actions」で、以下の値を設定します:

Secrets(暗号化されて保存されます):

  • SSH_PRIVATE_KEY - GitHubへのアクセス用のSSH秘密鍵
  • SLACK_WEBHOOK_URL - Slack通知用のWebhook URL

Variables(平文で保存されます):

トラブルシューティング

SSHキーのフォーマット問題

SSHキーを環境変数として設定し、それをファイルに書き込む際に「error in libcrypto」エラーが発生する場合があります。これは主にキーの最後の改行が失われていることが原因です。

解決策
YAMLのリテラルスタイル(|記号)を使用して改行を保持します:

- name: 環境変数からSSHプライベートキーを作成
  copy:
    content: |
      {{ ssh_private_key }}
    dest: "{{ target_user_home }}/.ssh/id_github"
    mode: '0600'
    owner: "{{ target_user }}"
    group: "{{ target_user }}"
  become: yes

Dockerの権限問題

「permission denied while trying to connect to the Docker daemon socket」というエラーが発生する場合、Dockerデーモンソケットへのアクセス権がないことが原因です。

解決策

  1. ユーザーをdockerグループに追加
  2. Dockerソケットのパーミッションを直接変更
  3. 新しいSSHセッションを開始して変更を反映
- name: Dockerグループが存在することを確認
  group:
    name: docker
    state: present
  become: yes

- name: ユーザーをdockerグループに追加
  user:
    name: "{{ target_user }}"
    groups: docker
    append: yes
  become: yes

- name: Docker設定の変更を反映するために新しいSSHセッションを作成
  meta: reset_connection

まとめ

この記事では、Ansibleを使用したGitHubプライベートリポジトリのクローン、Dockerイメージのビルド・実行、そしてGitHub Actionsによる自動化手順を紹介しました。

ポイント:

  1. SSH認証によるGitHubアクセス
  2. GitHub ActionsのSecrets/Variables活用
  3. SSHキーのフォーマット、Docker権限問題への対処

この方法で開発からデプロイまでの自動化を実現し、運用効率を向上させることができます。

Discussion