Anarchy In the 1K

CircleCIでタグ発行を契機にサーバへデプロイ

やりたいこと

 先日、以下の記事でCircleCIの導入を行いました。今回は、バージョン番号のタグ発行を契機とした、サーバへのデプロイを自動化します。
CircleCIの調査 - Anarchy In the 1K

事前準備

SSH

SSHキーの作成

 CircleCIがサーバに接続する為のSSHキーを、任意の端末上で以下の通り作成します。

$ssh-keygen -m pem
Generating public/private rsa key pair.
Enter file in which to save the key (・・・/.ssh/id_rsa): <出力先のフォルダ名/ファイル名>
Enter passphrase (empty for no passphrase): //何も入力せずEnter
Enter same passphrase again: //何も入力せずEnter

サーバに公開鍵の登録

 上記で作成した鍵のうち、公開鍵(拡張子がpub)を以下の通りサーバに登録します。

ssh-copy-id <SSH接続するサーバのユーザ名>@<SSH接続するサーバのホスト名> -i <パブリックキーのパス>

CircleCIに秘密鍵の登録

 以下ページの「追加手順」に従い、秘密鍵をCircleCIに登録します。
CircleCI に SSH 鍵を登録する - CircleCI

5.Private Key には、登録したい SSH 鍵の文字列を貼り付けます

上記に関しては、以下コマンドで出力された内容をコピーして貼り付けます。

cat <秘密鍵のパス>

 また、後ほど必要となる為、登録完了後の画面に表示される、Fingerprintの値を控えておいて下さい。

環境変数の定義

 下記の通り、人に知られたくない情報は、.circleci/config.ymlに記載するのではなく、プロジェクト設定より環境変数として定義するのが良い様です。
環境変数の使い方 - CircleCIより

.circleci/config.yml ファイルでは隠したい環境変数を宣言しないようにしてください。そのプロジェクトにアクセスできるエンジニア全員が config.yml ファイルの全文を見ることができます。 隠したい環境変数は CircleCI のプロジェクト設定やContexts設定で登録するようにしてください。

 そこで、Project Settings > Environment Variables > Add Environment Variableで、以下の通り環境変数*1を定義します。

Name Value
USER_NAME <SSH接続するサーバのユーザ名>
HOST_NAME <SSH接続するサーバのホスト名>

.circleci/config.ymlの設定

記載例

version: 2.1
jobs:
  build:
    machine:
      image: circleci/classic:edge
    steps:
      - checkout
      # 以下でbuild処理を行う。
      - run: <command01>
      - run: <command02>
      ...
  deploy:
    machine:
      image: circleci/classic:edge
    steps:
      - add_ssh_keys # (1)
          fingerprints:
            - <上述の「CircleCIにプライベートキーの登録」で控えたFingerprintの値>
      - run: ssh-keyscan ${HOST_NAME} >> ~/.ssh/known_hosts # (2)
      - run: |
          ssh ${USER_NAME}@${HOST_NAME} \<< EOF # (3)
            # 以下でdeploy処理を行う。
            <command01>
            <command02>
            ...
          EOF
workflows:
  version: 2.1
  build_and_deploy:
    jobs:
      - build:
          filters:
            tags: # (4)
              only: /.*/
      - deploy:
          requires:
            - build
          filters:
            tags: # (4)
              only: /^v[0-9]+(\.[0-9]+)*/
            branches: # (5)
              ignore: /.*/

解説

コンテナに対して、秘密鍵を登録する。(1)

known_hostsを作成する。(2)

 該当のコマンドで、接続先の公開鍵のフィンガープリントをknown_hostsに記録します。

サーバにSSHで接続する。(3)

 上述の「環境変数の定義」で登録した値を用いて、サーバにSSH接続を行います。例では、ヒアドキュメントを用いており、EOFまでのコマンドがサーバ上で実行されます。  <<に関して、バックスラッシュでエスケープする必要があります。(地味にハマりました。)

job実行の条件にタグ発行を追加する。(4)

ジョブの実行を Workflow で制御する - CircleCIより

CircleCI は明示的にタグフィルターを指定しない限り、 タグが含まれる Workflows は実行しません。

 上記に記載がある通り、タグ発行を契機としたjobの実行に関して、明示的に設定を行う必要があります。
 buildjobに関して、only: /.*/とすることで、全てのタグ発行を契機に、該当jobを実行する様にしています。
 一方でdeployjobに関して、only: /^v[0-9]+(\.[0-9]+)*/とすることで、バージョン番号のタグ発行を契機に、該当jobを実行する様にしています。

job実行の条件からブランチの更新を除く。(5)

 タグ発行を契機にしたjob実行に関して、明示的な設定が必要だったのに対して、ブランチの更新を契機にしたjob実行に関して、デフォルトで有効となっています。
 deployjobに関して、バージョン番号のタグ発行時のみ実行したい為、ignore: /.*/とすることで、ブランチの更新を契機に実行しない様にしています。

*1:CircleCIのExecutor上で有効な環境変数