Github Actions

CIをGitHub Actionsでやってみた

gitlabCIでやってたことをGitHub Actionsのドキュメント見て置き換えるだけ。
とはいえ最初workflowactionがごっちゃになっててうまく検索できなかった。
gitlabCIのgitlab-ci.ymlに当たるのはworkflowです。
actionは汎用するために処理単位で切り出した共通モジュールなので超便利っぽいけど一旦スルーすると理解しやすいと思う。

作ったもの

# ./.github/workflows/00.yml
name: "deploy"

# トリガをmasterへのpushに設定
on:
  push:
    branches:
      - "master"

jobs:
  # 別に名前は何でもよさそう
  build:
    # ジョブの実行環境を指定
    runs-on: ubuntu-latest
    # 環境変数定義
    env:
      GITHUB_SHA_S: $(echo ${GITHUB_SHA} | cut -c1-8)
    # ジョブのタスクを定義していく
    steps:
      # リポジトリチェックアウトするアクションを最初に実行
      - uses: actions/checkout@v2

      # DockerHubにログイン
      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      # Build&Push
      - run: docker build --build-arg baseurl=${{secrets.APP_IP}} -t ${{ secrets.DOCKERHUB_USERNAME }}/52steps:${{env.GITHUB_SHA_S}} .
      - run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/52steps:${{env.GITHUB_SHA_S}}
  deploy:
    runs-on: ubuntu-latest
    env:
      GITHUB_SHA_S: $(echo ${GITHUB_SHA} | cut -c1-8)
    steps:
      - uses: actions/checkout@v2
      # namespaceの作成
      - name: create ns
        uses: steebchen/kubectl@master
        env:
          KUBE_CONFIG_DATA: ${{ secrets.K8S_CONFIG }}
        with:
          args: apply -f ./deploy/ns.yml

      # k8sにdockerhubへのアクセス権限を作成
      - name: create secret
        uses: steebchen/kubectl@master
        env:
          KUBE_CONFIG_DATA: ${{ secrets.K8S_CONFIG }}
        with:
          args: |
            -n 52steps create secret docker-registry regcred \
              --docker-server=https://index.docker.io/v2/ \
              --docker-username=${{ secrets.DOCKERHUB_USERNAME }} \
              --docker-password=${{ secrets.DOCKERHUB_TOKEN }} \
              --docker-email=${{ secrets.DOCKERHUB_MAIL }} \
              -o yaml --dry-run | kubectl apply -f -

      # dockerHubのプライベートイメージにアクセスできるようにアクセス権限をnamespaceのdefaultアカウントに付与
      - name: add regcred namespace account
        uses: steebchen/kubectl@master
        env:
          KUBE_CONFIG_DATA: ${{ secrets.K8S_CONFIG }}
        with:
          args: |
            patch serviceaccount default \
              -p '{\"imagePullSecrets\": [{\"name\": \"regcred\"}]}' \
              -n 52steps

      # DBイメージをデプロイ
      - name: create db
        uses: steebchen/kubectl@master
        env:
          KUBE_CONFIG_DATA: ${{ secrets.K8S_CONFIG }}
        with:
          args: apply -f ./deploy/db.yml

      # アプリをデプロイ
      - name: Update deployment file
        run: TAG=${{ secrets.DOCKERHUB_USERNAME }}/52steps:${{env.GITHUB_SHA_S}} && sed -i "s|<IMAGE>|$TAG|" ./deploy/app.yml
      - name: create app
        uses: steebchen/kubectl@master
        env:
          KUBE_CONFIG_DATA: ${{ secrets.K8S_CONFIG }}
        with:
          args: apply -f ./deploy/app.yml

      # アプリのサービスをIngressで公開
      - name: create ingress
        uses: steebchen/kubectl@master
        env:
          KUBE_CONFIG_DATA: ${{ secrets.K8S_CONFIG }}
        with:
          args: apply -f ./deploy/ingress.yml

DockerHubへのログイン

自分のprivateレジストリにアクセスしたいのでdocker/login-actionアクションを利用してdockerLoginを行う。
DOCKERHUB_USERNAMEDOCKERHUB_TOKENはgithub actionsの設定画面から設定しておく。

# DockerHubにログイン
- name: Login to Docker Hub
  uses: docker/login-action@v1
  with:
    username: ${{ secrets.DOCKERHUB_USERNAME }}
    password: ${{ secrets.DOCKERHUB_TOKEN }}

Dockerfileのビルドとプッシュ

githubのリポジトリに登録したDockerfileをbuildしてpushする。
${{env.GITHUB_SHA_S}}はジョブの先頭で定義したGITHUB_SHA_S: $(echo ${GITHUB_SHA} | cut -c1-8)を参照しているだけ。
GITHUB_SHAはトリガとなったgitのcommitのハッシュ値でDockerImageのタグに使いたいけど長すぎるので短く切り取った。

# Build&Push
- run: docker build --build-arg baseurl=${{secrets.APP_IP}} -t ${{ secrets.DOCKERHUB_USERNAME }}/52steps:${{env.GITHUB_SHA_S}} .
- run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/52steps:${{env.GITHUB_SHA_S}}

k8sの操作

deployジョブではk8sの操作を行ってDockerImageのデプロイを行う。
steebchen/kubectlアクションを使ってkubectlを実行していく。
KUBE_CONFIG_DATAにはローカルの.kube/configをbase64化した文字列を設定する。

# namespaceの作成
- name: create ns
  uses: steebchen/kubectl@master
  env:
    KUBE_CONFIG_DATA: ${{ secrets.K8S_CONFIG }}
  with:
    args: apply -f ./deploy/ns.yml

k8sにDockerHubへのアクセス権を付与する

DockerHubのprivateレジストリを利用しているのでk8sにもアクセス権を与える必要がある。
k8sにはsecretの種別にdocker-registryへの権限が存在するのでそれを生成する。
secret作るときにapplyが使えないのでCIの2回目実行時に「既にあるけど」的なエラーが発生する。
そのためdry-runでymlファイルを生成してパイプでapplyに渡すといい感じになる。

# k8sにdockerhubへのアクセス権限を作成
- name: create secret
  uses: steebchen/kubectl@master
  env:
    KUBE_CONFIG_DATA: ${{ secrets.K8S_CONFIG }}
  with:
    args: |
      -n 52steps create secret docker-registry regcred \
        --docker-server=https://index.docker.io/v2/ \
        --docker-username=${{ secrets.DOCKERHUB_USERNAME }} \
        --docker-password=${{ secrets.DOCKERHUB_TOKEN }} \
        --docker-email=${{ secrets.DOCKERHUB_MAIL }} \
        -o yaml --dry-run | kubectl apply -f -

namespaceのdefaultアカウントに権限を付与

上記で作成したregcredをdeploymentファイルのimagePullSecretsに指定してもいいんだけどめんどくさいのでnamespaceのデフォルトアカウントにつけておく。
こうするとそのnamespace内で常に有効になる。

# dockerHubのプライベートイメージにアクセスできるようにアクセス権限をnamespaceのdefaultアカウントに付与
- name: add regcred namespace account
  uses: steebchen/kubectl@master
  env:
    KUBE_CONFIG_DATA: ${{ secrets.K8S_CONFIG }}
  with:
    args: |
      patch serviceaccount default \
        -p '{\"imagePullSecrets\": [{\"name\": \"regcred\"}]}' \
        -n 52steps

おじさんの感想

社内CI環境との違いはざっと以下の通り。

もの 社内 今回
CI gitlabCI github actions
k8s beremetalなk8s digitaloceanのk3s
docker registry gitlab registory dockerhub

CI環境は書き方の違いがあるくらいで、使っている範囲では出来る事に違いはなさそう。
k3sは今回の範囲ではk8sと同じ操作が可能で特にk3sを意識することはなかった。
dockerregistoryはdockerhub使う事にしたおかげでinsecure-registriesの設定は要らなかった。