それなりに適当にやってます

なんとなくそれっぽいメモとか備忘録とか適当に。 2018年5月にブログ移転しました。 古い記事は未整理です。

CircleCI + Packer でGCPにイメージを作成したメモ

ここ最近やっていることの諸々の続きで CircleCI を試すついでに、CircleCI を利用して git push で Packer を実行して、GCPにイメージを作成するところまでやってみた。

GCPサービスアカウントの準備

  • CircleCI から GCP のプロジェクトへアクセスするためのサービスアカウントを作成(json取得)

リポジトリの準備

  • BitBucket で非公開リポジトリを作成
  • CircleCI 側で作成したリポジトリが見れる事を確認
  • ADD PROJECTS > (作成したリポジトリの) Set Up Project を選択
  • Linux, Other の組み合わせで選択、表示された内容をそのままに、リポジトリに .circleci/config.yml を作成
  • start building のボタンを押して、ビルドが実行された事を確認

CircleCI プロジェクトの設定

環境変数

GCPサービスアカウント

GCP については公式のドキュメントに記載があるので、その手順で進める。

  • CircleCI の左側のメニューで BUILD を選択し、対象リポジトリの歯車マークをクリック、プロジェクトの詳細設定の画面に入る
  • Environment Variables > Add Variable を選択
  • 名前と値の入力ウインドウが表示されるので、名前に GCLOUD_SERVICE_KEY、値にサービスカウントのJSONをコピペする

GCPプロジェクト

続けて環境変数 GCLOUD_PROJECT にGCPのプロジェクトIDを設定

Packer

環境変数 USER もここで設定する。 後述する CircleCI の実行時 packer のバイナリが動かなかった事に対する対策 (設定しない場合 Current not implemented on linux/amd64 とか吐かれた)
値は BitBucket のユーザ名にしておいた。

SSH秘密鍵

CircleCI で実行される Docker 環境から、ビルドされる GCP インスタンスへアクセスするための秘密鍵を設定する。

  • プロジェクトの設定画面から SSH Permissions を選択し、Add SSH Key をクリック
  • Hostname は空欄、Private Key に秘密鍵をコピペし Add Key

これで鍵の登録は完了する。

CircleCI の設定

下記のような感じになった。

  • 色々やっていたけど、結局めんどくさくなって CentOS7 のイメージにしてしまった。
  • gcloud コマンドで CircleCI で起動した Docker コンテナのIP許可を設定している。
    • タグとして circleci を付け、packer で実行する base.json でも tags で同タグを指定している
  • google-cloud-sdk.repo のファイルは公式のもの
  • Packer + Ansibleの内容は前にやったやつ流用

.circleci/config.yml

version: 2
jobs:
  build:
    docker:
      - image: centos:latest
    environment:
      TZ: /usr/share/zoneinfo/Asia/Tokyo
    steps:
      - checkout
      - run:
          name: install ansbile (use validate) and packer
          command: |
            yum -y install epel-release
            yum -y install ansible curl unzip which openssh-clients
            curl -O https://releases.hashicorp.com/packer/1.2.4/packer_1.2.4_linux_amd64.zip
            unzip packer_1.2.4_linux_amd64.zip
            rm packer_1.2.4_linux_amd64.zip
      - run:
          name: packer validate
          command: ./packer validate ./base.json
      - run:
          name: gcloud command setup and packer build
          command: |
            if [ -n "${GCLOUD_SERVICE_KEY}" -a -n ${GCLOUD_PROJECT} ]; then
              echo ${GCLOUD_SERVICE_KEY} > ${HOME}/gcloud-service-key.json
              export GOOGLE_APPLICATION_CREDENTIALS="${HOME}/gcloud-service-key.json"
              cp google-cloud-sdk.repo /etc/yum.repos.d/
              yum -y install google-cloud-sdk
              gcloud auth activate-service-account --key-file=${HOME}/gcloud-service-key.json
              gcloud config set project ${GCLOUD_PROJECT}
            else
              echo "Not set environment"
              exit 1
            fi

            IP=`curl -f -s ifconfig.io`
            gcloud compute --project=${GCLOUD_PROJECT} firewall-rules update circleci \
            --source-ranges=${IP}/32 --target-tags=circleci

            ./packer build ./base.json

base.json

{
  "builders": [
    {
      "type": "googlecompute",
      "project_id": "packer-project",
      "source_image_family": "centos-7",
      "ssh_username": "packer",
      "image_name": "packer-example-{{timestamp}}",
      "zone": "asia-northeast1-a",
      "tags": "circleci"
    }
  ],
  "provisioners": [
    {
      "type": "shell",
      "inline": [
        "sudo yum -y update",
        "sudo yum -y --enablerepo=epel install ansible",
        "sudo sed -i '/sftp-server$/s/$/ -e/' /etc/ssh/sshd_config",
        "sudo systemctl restart sshd"
      ]
    },
    {
      "type": "ansible",
      "playbook_file": "ansible.yml"
    }
  ]
}

ansible.yml

- hosts: all
  become: true
  vars:
    project_id: packer-project
    region: asia-northeast1
    cloudsql_name : packer-cloudsql-master
  tasks:
    - name: install apache
      yum: name=httpd
    - name: create index.html
      shell: echo "Hello World!" > /var/www/html/index.html
    - name: apache restart
      service: name=httpd state=restarted enabled=yes
    - name: install mysql
      yum: name=mysql
    - name: Download file and force basic auth
      get_url: url=https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64
               dest=/usr/local/bin/cloud_sql_proxy
    - name: chmod cloud_sql_proxy
      file: path=/usr/local/bin/cloud_sql_proxy
            owner=root group=root mode=0755
    - name: create systemd.service file
      blockinfile:
        dest: /etc/systemd/system/cloudsql-proxy.service
        create: yes
        block: |
          [Unit]
          Description = CloudSQL Proxy Default
          After = network.target

          [Service]
          ExecStart = /usr/local/bin/cloud_sql_proxy -instances={{ project_id }}:{{ region }}:{{ cloudsql_name }}=tcp:3306
          ExecStop = /bin/kill ${MAINPID}
          ExecReload = /bin/kill -HUP ${MAINPID}
          Restart = always
          Type = simple

          LimitNOFILE=65535
          LimitNPROC=65535

          [Install]
          WantedBy = multi-user.target
    - name: systemctl reload
      systemd: name=cloudsql-proxy daemon_reload=yes
    - name: start cloudsql-proxy
      service: name=cloudsql-proxy state=restarted enabled=yes

CircleCI のバリデーションチェック

git push する前に確認するにはどうするんだろう?と思ったら ここに記述があった

$ sudo curl -o /usr/local/bin/circleci \
  https://circle-downloads.s3.amazonaws.com/releases/build_agent_wrapper/circleci \
  && sudo chmod +x /usr/local/bin/circleci
$ circleci config validate -c .circleci/config.yml

.circleci/config.yml is valid

結果

ローカルからの git push > CircleCI 経由でGCPイメージがビルドされるところまで確認した。

参考URL

以上