cover

Bitbucket Pipeline + Docker + Gradle による自動デプロイ実践

sorcererxw
プロジェクトのデプロイはいつも私にとって非常に悩ましいことでした。デプロイするたびに怠けてしまい、自動デプロイ(継続的インテグレーション)を面倒くさがってしまいますが、次にデプロイする時が来るとまた頭を悩ませることになります。

コンセプト

今日は思い切って自動デプロイの設定を完了させます。自分の要求は比較的シンプルで、単体サービスをデプロイするだけなので、Jenkinsを使うまでもなく、過剰な手段は必要ありません。ちょうどコードはBitbucketにホストされているので、Bitbucket Pipelineサービスを利用しました。これにより、いくつかのシンプルなワークフロータスクを定義でき、コードをpushするたびに自動的にビルドとデプロイが行われます。

(Bitbucket Pipeline の無料枠は毎月50分のビルド時間で、個人開発者には十分だと思われますが、パイプライン上で時間のかかる操作は極力避けるようにしてください)

また、ビルドプロセス中のエラー防止と将来のアーキテクチャアップグレードに備えて、プロジェクトをDockerイメージとしてパッケージし、イメージを独立してホストし、サーバーが最新のDockerイメージをプルしてコードを更新するようにしています。

パーツ

構想があるなら、「おもちゃを組み立てる」準備を始める必要がありますが、その前に、手元にある素材を確認する必要があります。

  • コードホスティングプラットフォーム+ビルドプラットフォーム: Bitbucket
  • Docker イメージのホスティング:Google Container Registry (gcr.io)
  • VPSインスタンス一つ
  • デプロイ対象ソフトウェア:Gradle + マルチモジュールSpring Bootプロジェクト

アセンブリ

GCR の設定

Google のドキュメントに従って、プロジェクトに gcr を有効にすることができます。

Gradle を使用して Docker をパッケージングする設定

Gradle Docker Build を処理するために、bmuschko/gradle-docker-plugin を使用します。ドキュメントによると、このプラグインは Spring Boot アプリケーションをゼロコンフィグでパッケージングすることをサポートしており、非常に便利です。

プロジェクトのルートディレクトリにあるbuild.gradleにプラグインを導入します。

buildscript {
    ext {
        ...
        gradleDockerPluginVersion = '4.0.4' // 查看插件的 Github Release 页面获得最新版本
        ...
    }
    repositories {
        ...
        gradlePluginPortal()
        ...
    }
    dependencies {
        ...
        classpath("com.bmuschko:gradle-docker-plugin:${gradleDockerPluginVersion}")
        ...
    }
}

子モジュールのbuild.gradleでプラグインを使用してパッケージを作成する必要があります。

apply plugin: 'com.bmuschko.docker-remote-api'
apply plugin: 'com.bmuschko.docker-spring-boot-application'

サブモジュールのbuild.gradleでDockerパッケージオプションを設定する

docker {
    registryCredentials {
        url = 'https://gcr.io'
        username = '_json_key'
        password = file(project.rootDir.path + '/gcr_keyfile.json').text
    }
    springBootApplication {
        baseImage = 'openjdk:8-alpine'
        ports = [8080]
        tag = "gcr.io/project/image:" + version
    }
}

registryCredentials とは、イメージホスティングの設定を行うためのノードです。url には、対応する GCR のアドレスを直接入力します。複数のアドレスがある場合は、実際のホスティング場所に応じて決定してください。username_json_key と直接入力し、認証方式が json ファイルであることを示します。passwordkeyfile.json の中身です。json の設定はプロジェクトのルートディレクトリにあり、サブモジュールの gradle が呼び出すため、相対パスを設定する必要があります。また、keyfile.json の取得方法については、GCR のドキュメントを参照してください。

springBootApplication ノードは最終的なイメージ情報を設定する部分ですが、これ以上の説明は省略します。

これで正常にパッケージングできます。もしローカルマシンにDockerがインストールされていて、ローカルの2375ポートが開いている場合は、直接テストを行うことができます。

gradlew :app:dockerPushImage

VPS の設定

VPSにDockerを設定する必要があるのは言うまでもありませんが、スムーズにプルを行うためには、GCloud SDKも適切に設定する必要があります。Googleのドキュメントに従ってください。

自動デプロイスクリプトの設定

パイプラインを使ってSSH操作を行うだけでは、エラーが発生した場合の対処ができないため、ホストにワンクリックデプロイスクリプトdeploy.shを設定しておく必要があります。その後、SSHでこのスクリプトを直接実行すればいいです。

以下カスタマイズ${カスタマイズが必要な内容}

cd ~
vi deploy.sh
#!/usr/bin/env bash

if [[  "$(docker ps -q -f name=${container name})" ]]; then
    docker update --restart=no ${container name}
    docker stop ${container name}
    docker rm ${container name}
fi

docker pull ${image name}
docker run -d --restart always -p 8080:8080 --name ${container name} ${image name}
chmod 777 deploy.sh

さて、次にホストで~/deploy.shを実行すれば、最新のイメージを自動的にデプロイできます。

Bitbucket と計算インスタンスの接続

Bitbucket 対応プロジェクトの <code>設定</code>-><code>SSH keys</code> に進み、新しい SSH キーを生成し、public key をコピーして vps に追加します。

また、計算インスタンスのホストアドレスをBitbucketのKnown hostsに追加する必要があります。

Pipeline スクリプトの作成

これは最も重要なステップと言えます。なぜなら、スクリプトを通じて事前に準備したリソースを連携させるからです。しかし、これが最後に行われるため、それほど重要ではないように感じられるかもしれません。

push 画像の認証は既に gradle 内で設定されているため、pipeline 環境で gcr の認証を行う必要はありません。

したがって、スクリプト全体は二つのステップに分けられます。

  • ビルド + プッシュ イメージ
  • vpsにsshで接続し、実行中の古いコンテナを停止して削除した後、新しいイメージをpullして再デプロイします。
pipelines:
  default:
    - step:
        name: Deploy to Docker
        image: openjdk:8
        caches:
          - gradle
          - docker
        services:
          - docker
        script:
          - chmod +x gradlew
          - bash ./gradlew :app:dockerPushImage
    - step:
        name: Deploy to Production
        deployment: production
        trigger: manual # 配置为手动, 使上线可控
        script:
          - ssh -T user@host deploy.sh
          - echo "Successful deployment to Production"