GithubActionsを使ったDockerImageのDeploy

2024年2月24日

はじめに

アプリケーションを開発する際に、Developerには開発環境一式としてDockerのimageを配布することがある。
DockerのimageをRegistryから引っ張ってくれば、開発者側はアプリケーションを開発するための環境準備を特別に行うことなく、実行することができる。
また、ユーザー間での環境の差分をなくすことができるので、環境起因によるデバッグの時間を減らすことが可能だ。
開発環境提供側は、開発環境の中身のUpdateがある度にDocker imageをUpdateする必要があるが、そこで手動の作業が発生すると、従来のイメージとは違った環境を提供してしまう可能性がある。できる限り自動化をすることで、開発者への環境のDeployもシームレスに行っていくことが求められている。
今回は、GithubActionsを使用して、Docker imageの作成とDocker hubへのPushまでを自動化してみる。

構築環境全体像

GithubとDockerHubへのアクセスができることを前提条件とする。

DockerHub
DockerHub
Developer
Devel…
Developer
Devel…
docker pull
docker pull
docker pull
docker pull
Provider
Provi…
Docker
コンテナ
Docker…
稼働中
稼働中
ベースイメージ
ベースイメージ
Dockerfile
Dockerfile
DockerImage
DockerImage
docker push
docker push
docker run
docker run
DockerImage
DockerImage
docker commit
docker commit
docker build
docker build
Viewer does not support full SVG 1.1

ベースイメージから、「docker run」コマンドでDockerコンテナを立ち上げる。
ここで特定の操作をコンテナ上で行い、環境のセットアップをすることも可能である。
「docker commit」コマンドで、Dockerコンテナ内でセットアップされた環境を反映した形でDockerImageを作成する。
その後、DockerFileを用いて「docker build」を行い最終的なDockerImageを作成する。
作成したDockerImageは、DockerHubへPushされDeveloperはそのDockerImageを用いることで、開発環境をセットアップすることができる。

Script

ディレクトリ構成は下記の通り。

|--.git
|--.github
|  |--workflows
|  |  |--create-docker-image.yaml
|--Dockerfile
|--README.md
|--test.txt
※ディレクトリ構成を表示するのに便利なコマンド(treeコマンドがない環境)

pwd;find . | sort | sed '1d;s/^\.//;s/\/\([^/]*\)$/|--\1/;s/\/[^/|]*/|  /g'

create-docker-image.yamlファイルは下記の通り。

.github/workflows/create-docker-image.yaml

---
name: create-docker-image
on:
  push:
  workflow_dispatch:

jobs:
  create-docker-image:
    runs-on: ubuntu-latest
    steps:
      - name: checkout-repository
        uses: actions/checkout@v3
        with: 
          path: docker-sample
          ref: feature/add-creation-docker-image

      - name: Login to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: docker-run
        id: check-container-id
        run: |
          docker run -dit --name my-apache-app -p 8080:80 -v "${{ github.workspace }}":/usr/local/apache2/htdocs/ httpd:2.4
          echo "::set-output name=container-id::$(docker ps | grep my-apache-app | awk '{print $1}')"

      - name: docker-commit
        id: check-image-id
        run: |
          echo "${{ steps.check-container-id.outputs.container-id }}"
          docker commit ${{ steps.check-container-id.outputs.container-id }} created-image-step1
          echo docker images | grep created-image-step1 | awk '{print $3}'
          echo "::set-output name=image-id::$(docker images | grep created-image-step1 | awk '{print $3}')"
          docker images

      - name: docker-build
        run: |
          echo "${{ steps.check-image-id.outputs.image-id }}"
          sed -i '1s/^/FROM ${{ steps.check-image-id.outputs.image-id }}\n/' docker-sample/Dockerfile
          echo "check Dockerfile"
          cat docker-sample/Dockerfile
          docker build -t ${host}/image-sample -f docker-sample/Dockerfile .
          docker images
          docker ps -a
          docker push ${host}/image-sample   

  confirm-docker:
    runs-on: ubuntu-latest
    needs: [create-docker-image]
    container: #起動するコンテナイメージを指定
      image: ${host}/image-sample #指定のdockerイメージを使用
    steps: #dockerコンテナ内でステップを実行
      - name: confirm-inside-docker
        run: | 
          cat /usr/local/apache2/htdocs/test.txt

コンテナを立ち上げたら、「docker ps」コマンドと「grep」コマンドを駆使してコンテナidやイメージidをパースし、ステップ間でパースした値を渡している。
「docker build」や「docker push」を実行してくれるactionsがあったが、今回はできる限りコマンドを直打ちして実現した。(本当はできる限りactionsを使ってメンテナンス性を上げる必要があるが、今回は動作を理解するためにあえてハードコーディングした。)
ポイントは、パースしたimage idをsedでDockerfileに追記している点。
Dockerfileは、下記の通りCOPYコマンドだけ記載。(workflowの中でFROM ${image id}を追記。)

COPY docker-sample/test.txt /usr/local/apache2/htdocs/

また、test.txtファイルには下記の通りsampleのコメントを記載。

sample file to incorporate in docker image

実行結果

実行ファイルからもわかる通り、「confirm-docker」jobを作成し、Dockerfileに記載した通りにimageの中にtest.txtが反映されているかを確認した。

Workflow全体

workflow全体
create-docker-image job

cretate-docker-image job
confirm-docker job

confirm-docker job

confirm-docker jobの実行結果より、作成したimageの中に意図通りtest.txtがが格納されていることが確認できた。

まとめ

今回は、GithubActionsとDockerを組み合わせることによって、開発環境のDeployの自動化を簡易バージョンで作成しました。
あらゆる場面で、多少やり方は違えど同じように環境を作成し、提供する現場が多いと思います。
基本をしっかりと押さえて、開発に活用していきたいと思います。

Posted by okuribito