astamuse Lab

astamuse Labとは、アスタミューゼのエンジニアとデザイナーのブログです。アスタミューゼの事業・サービスを支えている知識と舞台裏の今を発信しています。

gitlab-ci+kaniko+gcloudでCloudRunにアプリケーションをデプロイする

f:id:astamuse:20201110120825p:plain

11月です。寒いですね。ICPチームでgitlab-ci芸人をやっているchotaroです。
gitlab-ciと戦ったのも一年前
性懲りもなく、ややこなれてきた人向けのgitlab-ciのTIPS記事です。

日本語での情報があまりない分野ですので、誰かの役に立てば幸いです。
(なおこの記事を書いている段階でブログ当番を2ヶ月ほど滞納しております。土下座。

主な元ネタはこちらのgitlab公式doc

本記事のモチベーション

以下をモチベーションとしています。

  • 気軽にツール作ってdeployしたい。
  • gitlab-ciのjobからgcrにimageをpushしたい
  • ついでにそのままCloudRunにデプロイしたい
  • でもdind(docker-in-docker)はセキュリティ的に使いたくない(重要

jibなどもツールの選択肢にはなりうるのですが、CloudNative Buildpacksがdockerを必要とするため、dindを用いることが不適切なケースでは利用できません。

そこでここではgitlabの公式ドキュメントにも記載のある、kanikoを利用した実現方法を紹介していきます。

事前知識

kanikoとは

ものすごく端的に言えば、「dockerを使うことなく、Dockerfileからcontainer imageを作成し、リポジトリに pushするツール」です。

kaniko自体は、kubernates内でimageをbuildすることが主眼とされています。本記事ではあくまでも、container imageをdockerなしに作成するツールとして用います。

dockerfileの作成

kanikoはdockerを使いませんが、inputにDockerfileを必要とします。ProcfileなどではなくDockerfileなので、この点がややCloudNative Buildpacksなどと比べると開発者にとって少し敷居が高いかもしれません。

あくまでサンプルなので拘らず、GCPのdocにあるものを真似します。

Dockerfile

FROM node:15-slim

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install --only=production

COPY . ./

CMD [ "node", "index.js" ]

index.js

const express = require('express');
const app = express();

app.get('/', (req, res) => {
  const name = process.env.NAME || 'World';
  res.send(`Hello ${name}!`);
});

const port = process.env.PORT || 8080;
app.listen(port, () => {
  console.log(`helloworld: listening on port ${port}`);
});

package.json

{
    "name": "helloworld",
    "description": "Simple hello world sample in Node",
    "version": "1.0.0",
    "private": true,
    "main": "index.js",
    "scripts": {
      "start": "node index.js",
      "test": "mocha test/index.test.js --exit",
      "system-test": "NAME=Cloud test/runner.sh mocha test/system.test.js --timeout=30000",
      "lint": "eslint '**/*.js'",
      "fix": "eslint --fix '**/*.js'"
    },
    "author": "Google LLC",
    "license": "Apache-2.0",
    "dependencies": {
      "express": "^4.17.1"
    },
    "devDependencies": {
    "got": "^11.0.0",
    "mocha": "^8.0.0",
    "supertest": "^4.0.2"
    }
}

起動して8080にアクセスするとHello World!という表示だけ出ます。

kanikoを使ったbuild

kanikoは引数で三つ指定が必要です。

  • docker-file
    • build対象のDockerfileはどこに置いてあるか。
      • gitlab-ciであれば$CI_PROJECT_DIRなど。
  • context
    • どこのソースを使用するか。kubernatesでの利用が主眼なので、リモートリポジトリなども指定できます。
      • gitlab-ciで特定のrepositoryでciする場合だと、素直に$CI_PROJECT_DIRなどでOKです。
  • destination
    • この設定値がpush先になります。
      • 例えばgcrのフルパス。(ex: gcr.io/<プロジェクト名>/<image名>

executorを対象にdocker runすればそのままdestinationに作成したimageがpushされる形です。

また、gcrにpushしたい場合GCPでの認証認可が必要になりますが、その他のGCPツール群と同じく$GOOGLE_APPLICATION_CREDENTIALSの環境変数にcredentialファイルのpathを渡してあげればOKです。

gcr上のイメージをcloud run上へdeployする

pushしたdocker imageをcloud run上にdeployするには、gcloudのコマンドを使えばOKです。gcrへのpushで使ったservice accountにこの権限も付与しておくと管理すべき認証情報が一つのservice accountにまとまるのでエコです。

公式ドキュメントも参考に、コンテナイメージを使ってgcloudコマンドでdeployしましょう

gcloud run deploy <サービス名> --image <imageのpush先> --platform managed --region <region名> 

実際に試してみる

gitlab-ci.yml

このような形になりました(ExecutorにはDocker Machineを使用しています)

stages:
  - build
  - deploy

before_script:
  - echo 'set up  credentials'
  - echo $CREDENTIAL > $CI_PROJECT_DIR/key.json
  - export GOOGLE_APPLICATION_CREDENTIALS=$CI_PROJECT_DIR/key.json

build: 
  stage: build  
  image:
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]  
  script:
    - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $DESTINATION

deploy:
  stage: deploy
  image: google/cloud-sdk:alpine
  script:
    - gcloud auth activate-service-account --key-file=key.json
    - gcloud config set project $GCP_PROJECT_NAME
    - echo y | gcloud auth configure-docker
    - gcloud info
    - echo y | gcloud run deploy kaniko-sample --image $DESTINATION --platform managed --region <region名>

ポイントは以下の点です。

  • buildとdeployでjobを分ける
  • 環境変数にcredentialなどの情報は外出しする(git管理下に鍵情報は置きたくないので
  • before scriptで認証情報のセットアップを行う

buildとdeployでjobを分ける

kanikoのimageはdebugで利用します(gitlab公式docも参照ください

また、素のalpineなどにgcloudを入れるのは大変なので、gcloudのimageをそのまま使うためtaskを分けています。

環境変数にcredentialなどの情報は外出しする

gitlab-ciのvariablesに下記を設定します。

  • GCP_PROJECT_NAME
    • GCP上のプロジェクト名
  • CREDENTIAL
    • サービスアカウントの認証情報
  • DESTINATION
    • gcrの指定

before scriptで認証情報のセットアップを行う

  - echo 'set up  credentials'
  - echo $CREDENTIAL > $CI_PROJECT_DIR/key.json
  - export GOOGLE_APPLICATION_CREDENTIALS=$CI_PROJECT_DIR/key.json

ややトリッキーな書き方になってはいますが、variablesに設定した認証情報を書き出します。

    - gcloud auth activate-service-account --key-file=key.json
    - gcloud config set project $GCP_PROJECT_NAME
    - echo y | gcloud auth configure-docker

gcloudでそのkeyをもとにサービスアカウントとしての認証設定を行います。これでgcloudのセットアップはOK

実行後の確認

gitlab-ciの実行結果を確認し、Service URLにアクセスしてHello World!を確認します。

Deploying container to Cloud Run service [<サービス名>] in project [<プロジェクト名>] region [<リージョン名>]
Deploying...
Creating Revision...................................................................................done
Routing traffic......done
Done.
Service [<サービス名>] revision [<サービス名>-00004-but] has been deployed and is serving 100 percent of traffic.
Service URL: https://<url>

trouble shooting系(ここでつまりました

  • gcloud run の際にSERVICEがないと言われる
    • ちゃんとhelpをよみましょう。
    • gcloud run deploy <SERVICE名称> <--で始まるその他オプション>という構文です。
  • gcloud run の際にregionが設定されてないと言われる
    • ちゃんと(ry
    • 設定しましょう。 --regionオプションです
  • 403が出て表示できない
    • これが出るのは主に、デプロイしたアプリが権限を必要とする状態になっており、かつアクセス者に権限がない場合です
    • console上でアクセスする人(gcp上のメンバー)に権限を付与すればそのメンバーがアクセスできるようになります。
      • あくまでサンプルやリクエストを複数受けても問題ない場合のみ使うべきTIPSではありますが、--allow-unauthenticatedオプションをつけてdeployすることで誰でもアクセスできるようになります。

まとめ

ざっくりとした解説にはなりますが、以上です。
趣味と実務の境目みたいなTIPSでしたが、こういう積み重ねが後々新しいことをやろうとした時に効いてくると信じています。

やってみた感想としては、Dockerfileを用意すればどんなアプリケーションでも原則このやり方でdeployできるはずなので、社内ツールのようなものにも活用していけたら気軽にいろいろ試していけそうかな、という感じです。

ICPとして今後本番利用したりしていくかは未知数ですが、jenkinsでの運用に限界があるのも事実なので、この辺りのアンテナも個人的には立てていきたいところだと思っているところです。

さて最後にはなりますがアスタミューゼでは引き続き好奇心豊富な(?)メンバーを募集しています。
業務やドメイン的には他の方の記事がどれもかなり興味深い内容にはなっておりますので、そちらも読んでいただきビビッときたらこちらよりご連絡いただければと思います。では!

参考にさせていただいたもの

Copyright © astamuse company, ltd. all rights reserved.