GCPで基本に戻って始める実践 Infrastructure as code再入門#4

こんにちは! 2020年2月からSREチームにJoinしました木村です!
仕事をする上での座右の銘は「明日交通事故にあってもシステムと仕事を回せるようにすること」です。

基本に戻って始める。と表題では書いていますが、私元々はAWS職人でGCPに本格的にコミットしてからまだ3ヶ月位です!

なのでヒィヒィ?言いながらGCPのキャッチアップに努めているわけですが今回は過去にAWSで得たInfrastructure as Codeの知識とビザスクに入社してキャッチアップで培ったGCPの知識を元に基本に戻って始めるGCPのInfrastructure as Code再入門ということで書かせていただきます。

前回はAnsibleのplaybookの実践的な使い方迄を説明しましたので、今回はAnsibleをProvisioningしたOSImageをPackerで作成する所までやっていきたいとおもいます。

その他のGCPで基本に戻って始める実践 Infrastructure as code再入門シリーズはこちら

今回のGCPのInfrastructure as code再入門シリーズでのゴールイメージ

  • TerraformでCompute Instanceを作成
  • Compute Instanceに対してAnsibleでNginxをインストールする
  • AnsibleでProvisoningされたサーバーの状態をPackerでImage化 <= 今ココ

始める前に用意していただきたいもの

動作環境(ホストOS)

  • ホストOS: Mac OSX
  • Python 3.7.5
  • Ansible (2.9.7)

動作環境(ゲストOS)

  • CentOS7

サーバー管理の問題点

前回はAnsibleを用いてNginxのProvisioning迄行いましたが、サーバーの運用に関してはまだこれだけではいくつか問題点があります。

  • インストールしたmoduleのバージョンが古くなってしまってリポジトリからダウンロードできない
  • HTTPリクエストが取得する側の状況によってエラーになる
  • などなど

実際にAnsibleを運用をし始める冪等性の担保がしづらい問題がでてきます。
そこでProvisionが成功した時点のOS Imageを作成することに冪等性の担保問題が一つの解決策になります。

(これをゴールデンイメージを作成する。と呼ばれています)

Packerでゴールデンイメージを作成する

PackerはOS Imageを作成するツールです。
今回はPackerでGCPとの設定の仕方、Ansibleの連携方法について説明をしていきます。

Packerをインストールする

homebrewでインストールします

brew install packer

バージョンを確認します

$ packer --version
1.5.4

Templateを記述する

# packer.template.json

{
  "variables": {
    "stage": "dev",
    "version": "v1"
  },
  "builders": [
    {
      "type": "googlecompute",
      "account_file": "secrets/gcp-key-ansible-sa-dev.json",
      "project_id": "{{user `gcp_project`}}",
      "source_image": "centos-7-v20200420",
      "network": "default",
      "disk_size": "20",
      "ssh_username": "packer",
      "ssh_port": 22,
      "zone": "asia-northeast1-c",
      "image_name": "sample-image-{{user `stage`}}-{{user `version`}}",
      "image_description": "Compute EngineのImageの詳細説明",
      "image_family": "sample-image-centos7",
      "machine_type": "n1-standard-1"
    }
  ],
  "provisioners": [
    {
      "type": "ansible",
      "ansible_env_vars": [ "ANSIBLE_CONFIG=ansible.cfg"],
      "extra_arguments": [
        "-v",
        "--extra-vars",
        "resource_stage={{ user `stage`}} gcp_project={{ user `gcp_project` }}"
      ],
      "user": "packer",
      "playbook_file": "site.yml"
    }
  ]
}

それぞれのセクションについて説明します

variables

名前の通り変数の設定です

"variables": {
    "stage": "dev",
    "version": "v1"
}

template内でこの変数が

{
    "stage": "{{user `stage`}}"
}

のように使えます。またPacker実行時の引数で変数を上書きすることが出来ます。

$ packer build -var "stage=stg" packer.template.json

変数の上書きは -var-fileと引数オプションでも指定可能です

$ packer build -var-file=variables.json packer.template.json
# variables.json

{
    "stage": "stg"
}

builders

GCPの設定を記述します

  "builders": [
    {
      "type": "googlecompute",
      "account_file": "secrets/gcp-key-ansible-sa-dev.json",
      "project_id": "{{user `gcp_project`}}",
      "source_image": "centos-7-v20200420",
      "network": "default",
      "disk_size": "20",
      "ssh_username": "packer",
      "ssh_port": 22,
      "zone": "asia-northeast1-c",
      "image_name": "sample-image-{{user `stage`}}-{{user `version`}}",
      "image_description": "Compute EngineのImageの詳細説明",
      "image_family": "sample-image-centos7",
      "machine_type": "n1-standard-1"
    }
  ]

Key名を見れば大体わかるかと思いますが、ポイントだけ

  • account_fileはAnsibleで使用したサービスアカウントのキーファイルを指定してください(このサービスアカウントがCompute Engine Instanceの作成からPackerを実行するにあたっての処理をおこないます)
  • project_idはGCPアカウントのプロジェクトIDを指定してください
  • source_imageはCompute EngineのImageの名前を指定してください
  • image_familyはCompute EngineのImageのfamily名です。Compute Engineのイメージの詳細ついては公式ドキュメントを参照してください
  • machine_typeはPackerがイメージをビルドをする時のインスタンスサイズです。今回はサンプルなのでインスタンスサイズは小さめに選択していますが、インスタンスサイズを小さくするとビルド迄の時間が長いので普段はでかいインスタンスサイズを設定して高速でビルドするようにすると効率よくイメージが作成できます。

provisioners

Ansibleに関する設定を記載します。前回のコマンドをベースに設定していけばよいかと思います。

  "provisioners": [
    {
      "type": "ansible",
      "ansible_env_vars": [ "ANSIBLE_CONFIG=ansible.cfg"],
      "extra_arguments": [
        "-v",
        "--extra-vars",
        "stage={{ user `stage`}} gcp_project={{ user `gcp_project` }}"
      ],
      "user": "packer",
      "playbook_file": "site.yml"
    }
  ]

実際にPackerを動かしてみる

$ export MY_GCP_PROJECT="{your gcp project id}"
$ packer build -var "stage=dev" -var "gcp_project=$MY_GCP_PROJECT" packer.template.json
.
.
.
==> Builds finished. The artifacts of successful builds are:
.
.
.

Ansibleのproviosioningが動作していることを確認してください。

Compute EngineのImageを作成することでの注意点

イメージを再度同じ名前で焼き直す場合はオプションに-forceを指定しないとエラーになるので注意してください。

イメージ名は世代バージョンの付与(v1,v2)をおすすめします。
これはイメージ側の不具合があった場合の調査等に便利です。

まとめ

Packerは最初作成する迄億劫なのですが、イメージを作成すると

  • 社内全体で必要なパッケージのインストール後の社内共通イメージ
  • 各サービス単位のイメージ

とタスクの分離が出来たり

  • Provisioningが長い問題の改善
  • Provisionが完了した時点でサービスが起動できる状態までProvisioningを作り込めば障害時にイメージからの復元で安全に復元できたり
  • 冗長化する場合のインスタンスのスケールインの自動化

等様々なメリットが生まれます。

今回GCPで基本に戻って始める実践 Infrastructure as code再入門の最後になりますが、もっともっと深くビザスクのSREのお仕事を知りたい方は、、、、、

エンジニア積極採用中です!!

ビザスクでは一緒に働くエンジニアさん積極採用中です。
時期的にビデオ通話での面談になると思うので、ビザスクにちょっとでも興味のある方はいつもより気軽にお話を聞きに来ることができるかなと思います。


エンジニアを募集しています

ビザスクでは、エンジニアとして働きたい方を募集しています。
ご興味のある方は下記よりお気軽にご連絡ください。