July Tech Festa 2019で発表した「[B10] 泣きながらAWS CodeBuidとPacker/Ansible provisionerでつくるWindows AMI」のセッションスライドです。
https://2019.techfesta.jp/speakers#B20
泣きながら!AWS CodeBuidとPacker/Ansible provisionerでつくるWindows AMI_・)つかまん(塚本 正隆)日本ヒューレット・パッカード株式会社Pointnext HybridIT Practicehttp://bit.ly/JTF2019-B20
View Slide
誰?• 名前:_・) つかまん (@tsukaman)• 仕事:HPE / Pointnext Hybrid IT Practice• 役割:Cloud Solution Architect、打楽器• 書籍:Ansible実践ガイド 第3版、Raspberry Pi〔実用〕入門• 好き:せがれいじり、ガジェットIYH、眼鏡、楽しいこと• 参加:Cloud Native Days Tokyo、RancherJP、Tokyo HackerSpace 他• 最近:合気道で白帯脱出しました(まだ茶帯)2
なにしたの︖ま ず は 出 来 上 が っ た も の を 紹 介3
これをしました。PowerShellAMIInstanceSnapshotEBSEC2AWS CodeBuildProvisionerPR/MergeWebHookRunCustom Image4
これをしました。PowerShellAMIInstanceSnapshotEBSEC2AWS CodeBuildProvisionerPR/MergeWebHookRunCustom Image流れコードを書いてPRすると⼀旦CodeBuild上でPackerのValidationが⾛ります。結果が問題なさそうだったらPRをMergeします。そうするとCodeBuild上でPackerによりAMI作成までの⾃動処理が流れます。処理が終わるまで珈琲を飲みます。5
これをしました。PowerShellAMIInstanceSnapshotEBSEC2AWS CodeBuildProvisionerPR/MergeWebHookRunCustom ImageGithubコードリポジトリとして、CodeBuild や Packer が使う各種ファイルの管理を⾏う。 Ansible やPowerShell など、Packer が使う各 Provisioner のコードも併せて管理する。Pull Request や Mergeを契機に WebHook にて CodeBuild へ通知する。6
これをしました。PowerShellAMIInstanceSnapshotEBSEC2AWS CodeBuildProvisionerPR/MergeWebHookRunCustom ImageAWS CodeBuild予め定義した内容に従い、⾃動処理を⾏う。今回はGitHubからのWebHookを契機に、カスタマイズDockerイメージからコンテナを起動し、その中でPackerの処理を実⾏する。AWSを利⽤する場合は、安価で柔軟性も⾼く、使いやすい⾃動化ツール。7
これをしました。PowerShellAMIInstanceSnapshotEBSEC2AWS CodeBuildProvisionerPR/MergeWebHookRunCustom ImageDocker(カスタムイメージ)CodeBuildの⾃動処理では、実⾏環境としてDockerコンテナを利⽤する。処理の内容に合わせて、利⽤するDockerイメージを指定するが、今回はWindowsに対して⾏う処理内容に併せて、必要なツール群を配置したカスタムイメージを⽤意。8
これをしました。PowerShellAMIInstanceSnapshotEBSEC2AWS CodeBuildProvisionerPR/MergeWebHookRunCustom ImagePackerHachiCorp社が中⼼に開発をしているOSS。各IaaS基盤や仮想化環境に合わせたマシンイメージをコードから⾃動⽣成することができる。イメージのカスタマイズにはProvisionerと呼ばれる様々なコンポーネントを組み合わせることが可能。9
これをしました。PowerShellAMIInstanceSnapshotEBSEC2AWS CodeBuildProvisionerPR/MergeWebHookRunCustom ImageProvisionerPackerでカスタムイメージを作成する際に、ベースとなるインスタンスに対して様々な処理をするためのコンポーネント。処理の内容やお好みの定義⽅法に合わせてツールを選択できる。今回はAnsible、PowerShell、Windows Shell、Fileを利⽤。10
これをしました。PowerShellAMIInstanceSnapshotEBSEC2AWS CodeBuildProvisionerPR/MergeWebHookRunCustom ImageAWS EC2 / EBS泣く⼦も黙るPublic Cloud界の重鎮であるAWS様による仮想サーバおよび仮想ボリュームを提供するサービス。EC2ではサーバインスタンスの起動に、ベースとなるAMIを利⽤するが、今回はカスタマイズしたWindows AMIをPackerで作るよ︕って話。11
これをしました。PowerShellAMIInstanceSnapshotEBSEC2AWS CodeBuildProvisionerPR/MergeWebHookRunCustom Image社畜(私)泣く⼦。この仕組みを作るため、夜なべを繰り返しながら⾃動処理が流れては死んでいくのを⽣暖かく⾒守るというお仕事をする。⾃分でPRして⾃分でMergeするという作業を200回くらいやってた。仕組みが出来た後は、他者に引き継いで去る⼈。12
動かすこ い つ ・ ・ ・ 動 く ぞ ︕ ( た ぶ ん )13
動かすこ い つ ・ ・ ・ 動 く ぞ ︕ ( た ぶ ん )14デモ
内容の紹介使 っ た コ ー ド や 設 定 と か15
カスタムDockerイメージ• CodeBuildの⾃動処理で利⽤するDockerイメージ– CodeBuildが提供するマネージドのイメージもある• この場合、必要なツールは処理の都度インストールすることになる– 必要な処理に併せたイメージを事前に⽤意することもできる• 処理時間を短縮したい場合は⽤意した⽅が無難• イメージはアクセス出来る場所ならどこで保管しても良い– DockerHubやAmazon ECRなど、任意のDockerレジストリを利⽤可– レジストリの認証情報を設定することも可能• 今回利⽤しているDockerイメージはDockerHubで公開中– https://hub.docker.com/repository/docker/tsukaman/jtf2019-packer-ansible-docker-image16
Dockerfilehttps://github.com /tsukaman /jtf2019-packer-ansible-docker-imageFROM ansible/ansible-runner:1.3.4ENV PACKER_VERSION 1.4.5WORKDIR /usr/local/binRUN set -x && ¥yum install -y https://centos7.iuscommunity.org/ius-release.rpm && ¥yum update -y --exclude='ansible*' && ¥yum install -y jq python2-pip tree unzip wget && ¥rm -rf /var/cache/yum/* && yum clean all && ¥wget -q https://releases.hashicorp.com/packer/${PACKER_VERSION}/packer_${PACKER_VERSION}_linux_amd64.zip && ¥unzip ./packer_${PACKER_VERSION}_linux_amd64.zip && ¥rm ./packer_${PACKER_VERSION}_linux_amd64.zip && ¥pip install --upgrade pip && ¥pip install awscli boto pywinrm171⾏で⼊⼒
AWS CodeBuildのBuild Project• CodeBuildでは⾃動処理単位として「Build Project」を作成する• AWSコンソールのほか、AWS CLIやTerraformでも設定が可能• Build Projectの設定前にやっておく準備の例– ⾃動処理で利⽤するDockerコンテナイメージ– GithubのRepositoryの作成– SystemsManagerのパラメータストアへ機密情報の登録• パラメータストアでは機密情報を暗号化して保管が可能– CodeBuildからはこの値を安全に実⾏環境コンテナへ引き渡せる• GitHubでコード化したくない情報を登録すると良い– Ansible vaultのパスワードとか18
AWS Systems Managerのパラメータストア19
AWS Systems Managerのパラメータストア20ここで⼊⼒する名前は、CodeBuildの変数定義で⼊⼒するので、覚えておく。
AWS Systems Managerのパラメータストア21暗号化させたい場合は「安全な⽂字列」を選択し、値を⼊⼒する。保管時はKMSキーによって暗号化される。
AWS CodeBuildのビルドプロジェクト22続いて、CodeBuildでのBuild Project新規作成。まずは名前、説明、タグ情報などを⼊⼒する。
AWS CodeBuildのビルドプロジェクト23送信元では、今回はOAuth連携したGithubのリポジトリを指定。クローンの深さをFullとし、ビルドステータスレポートも有効化。
AWS CodeBuildのビルドプロジェクト24Web Hookから移動実⾏する内容を指定。柔軟な設定が可能。今回はPRの作成/更新/リオープンおよびmasterへのプッシュを契機に実⾏させる。
AWS CodeBuildのビルドプロジェクト25処理の実⾏環境となるコンテナ情報を指定。今回は前述したDockerHub上のコンテナイメージを指定している。
AWS CodeBuildのビルドプロジェクト26実⾏コンテナに付与するサービスロールを選択する。今回はデフォルトのまま、ロールを新規作成させて、あとから必要な権限をIAMで追加する。その他の項⽬はデフォルトで良い。
AWS CodeBuildのビルドプロジェクト27コンテナ内の環境変数を定義する。ここではパラメータストアで作成した値を参照させている。その他のものはデフォルトで良い。
AWS CodeBuildのビルドプロジェクト28キャッシュは指定しなくても動作上は問題ないが、指定すると⼀部の動作が⾼速化する。
AWS CodeBuildのビルドプロジェクト29ログの出⼒先としてCloud Watch Logsを指定し、グループ名/ストリーム名を指定する。実⾏結果を確認する為にも、設定すると良い。
AWS IAM ロールの権限ポリシー追加30⾃動作成されたサービスロールへ権限ポリシーを追加する。今回は「AmazonEC2FullAccess」と「IAMFullAccess」を追加する。
紹介するファイル⼀覧https://github.com/tsukaman /jtf2019-packer-ansible-aws├ README.md├ ansible│ ├ after_reboot.yml│ ├ connection_plugins│ │ └ packer.py│ └ site.yml├ buildspec.yml├ files│ └ ansible.cfg[ 右へ続く ][ 左からの続き ]├ packer.json├ powershell│ ├ ConfigureRemotingForAnsible.ps1│ └ sysprep.ps1├ scripts│ ├ build.sh│ ├ run.sh│ └ validate.sh└ win-userdata.txt31“packer.py” はPackerがWindowsインスタンスに対してAnsibleで処理を⾏う為に必要なプラグインスクリプト。PackrのGithubにて配布している。“ConfigureRemotingForAnsible.ps1” はWindowsがAnsibleの接続を受け付ける為に必要な設定を⾏う為のPowerShellスクリプト。AnsibleのGithubにて配布している。
紹介するファイル⼀覧https://github.com/tsukaman /jtf2019-packer-ansible-aws├ README.md├ ansible│ ├ after_reboot.yml│ ├ connection_plugins│ │ └ packer.py│ └ site.yml├ buildspec.yml├ files│ └ ansible.cfg[ 右へ続く ][ 左からの続き ]├ packer.json├ powershell│ ├ ConfigureRemotingForAnsible.ps1│ └ sysprep.ps1├ scripts│ ├ build.sh│ ├ run.sh│ └ validate.sh└ win-userdata.txt32• ConfigureRemotingForAnsible.ps1 の⼊⼿先https://github.com/ansible/ansible/blob/devel/examples/scripts/ConfigureRemotingForAnsible.ps1• packer.py の⼊⼿先https://github.com/hashicorp/packer/blob/master/examples/ansible/connection-plugin/2.6.x/packer.py
紹介するファイル⼀覧https://github.com/tsukaman /jtf2019-packer-ansible-aws├ README.md├ ansible│ ├ after_reboot.yml│ ├ connection_plugins│ │ └ packer.py│ └ site.yml├ buildspec.yml├ files│ └ ansible.cfg[ 右へ続く ][ 左からの続き ]├ packer.json├ powershell│ ├ ConfigureRemotingForAnsible.ps1│ └ sysprep.ps1├ scripts│ ├ build.sh│ ├ run.sh│ └ validate.sh└ win-userdata.txt33• ConfigureRemotingForAnsible.ps1 の⼊⼿先https://github.com/ansible/ansible/blob/devel/examples/scripts/ConfigureRemotingForAnsible.ps1• packer.py の⼊⼿先https://github.com/hashicorp/packer/blob/master/examples/ansible/connection-plugin/2.6.x/packer.py
AWS CodeBuildのbuildspec.yml• CodeBuildではどのような処理を⾏うかの内容を buildspec.yml で定義することができる– ソースコードリポジトリのルートディレクトリに配置する• 配置場所やファイル名は違うものを指定することも可能– このファイルの代わりに直接ビルドコマンドを定義することもできる• YAML形式で様々な設定を柔軟に⾏える– 変数定義やフェーズ毎の細かい処理内容などを定義できる– https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-spec-ref.html34
buildspec.ymlversion: 0.2phases:install:commands:- ansible –version- packer --version- aws --versionbuild:commands:- echo "$VAULT_PASS" > vault_password_file- /bin/sh scripts/run.sh35やっていることは⾮常にシンプル。事前処理で各ソフトウェアのバージョンを出⼒。実処理ではAnsibleVault⽤のパスワードファイルを環境変数(パラメータストアの値から定義したアレ)から作成し、その後 run.sh を呼び出している。
紹介するファイル⼀覧https://github.com/tsukaman /jtf2019-packer-ansible-aws├ README.md├ ansible│ ├ after_reboot.yml│ ├ connection_plugins│ │ └ packer.py│ └ site.yml├ buildspec.yml├ files│ └ ansible.cfg[ 右へ続く ][ 左からの続き ]├ packer.json├ powershell│ ├ ConfigureRemotingForAnsible.ps1│ └ sysprep.ps1├ scripts│ ├ build.sh│ ├ run.sh│ └ validate.sh└ win-userdata.txt36• ConfigureRemotingForAnsible.ps1 の⼊⼿先https://github.com/ansible/ansible/blob/devel/examples/scripts/ConfigureRemotingForAnsible.ps1• packer.py の⼊⼿先https://github.com/hashicorp/packer/blob/master/examples/ansible/connection-plugin/2.6.x/packer.py
run.sh#!/bin/sh -xeif echo ${CODEBUILD_SOURCE_VERSION} | grep -q 'pr/ʼ ; then/bin/sh scripts/validate.shelse/bin/sh scripts/build.shfi37run.sh では、CodeBuildが⾃動的に設定する環境変数「CODEBUILD_SOURCE_VERSION」に「pr/」が含まれるかどうかで実⾏するシェルスクリプトを切り替え。Pull-Reqの場合のみ、pr/が含まれる。この処理はmixiのSREであるIsao Shimizu⽒の記事を参考に実装。参考︓Terraform どこで実⾏していますか︖|Mediumhttps://medium.com/mixi-developers/terraform-on-aws-codebuild-44dda951fead
build.sh#!/bin/sh -xepacker validate packer.json38#!/bin/sh -xemkdir /etc/ansiblecp -f ${CODEBUILD_SRC_DIR}/files/ansible.cfg /etc/ansible/ansible.cfgpacker build -color=false packer.jsonvalidate.shPRかPush/Mergeかで、packerのサブコマンドが変わる。なおbuildにおいては、CodeBuildのログコンソールがカラーコードを上⼿く処理/表⽰できないため -color=false をつけて実⾏している。
紹介するファイル⼀覧https://github.com/tsukaman /jtf2019-packer-ansible-aws├ README.md├ ansible│ ├ after_reboot.yml│ ├ connection_plugins│ │ └ packer.py│ └ site.yml├ buildspec.yml├ files│ └ ansible.cfg[ 右へ続く ][ 左からの続き ]├ packer.json├ powershell│ ├ ConfigureRemotingForAnsible.ps1│ └ sysprep.ps1├ scripts│ ├ build.sh│ ├ run.sh│ └ validate.sh└ win-userdata.txt39• ConfigureRemotingForAnsible.ps1 の⼊⼿先https://github.com/ansible/ansible/blob/devel/examples/scripts/ConfigureRemotingForAnsible.ps1• packer.py の⼊⼿先https://github.com/hashicorp/packer/blob/master/examples/ansible/connection-plugin/2.6.x/packer.py
ansible.cfg[defaults]gathering = smartfact_caching = jsonfilefact_caching_connection = /tmp/facts_cache# two hours timeoutfact_caching_timeout = 720040また、packer buildの実⾏の前処理として、/etc/ansible にコピーしていたansible.cfg はfactキャッシュさせる為のカスタマイズ。なくても良いが、複数のPlaybookを流す際などは時間が余計にかかるので必要に応じて設定すると吉。
紹介するファイル⼀覧https://github.com/tsukaman /jtf2019-packer-ansible-aws├ README.md├ ansible│ ├ after_reboot.yml│ ├ connection_plugins│ │ └ packer.py│ └ site.yml├ buildspec.yml├ files│ └ ansible.cfg[ 右へ続く ][ 左からの続き ]├ packer.json├ powershell│ ├ ConfigureRemotingForAnsible.ps1│ └ sysprep.ps1├ scripts│ ├ build.sh│ ├ run.sh│ └ validate.sh└ win-userdata.txt41• ConfigureRemotingForAnsible.ps1 の⼊⼿先https://github.com/ansible/ansible/blob/devel/examples/scripts/ConfigureRemotingForAnsible.ps1• packer.py の⼊⼿先https://github.com/hashicorp/packer/blob/master/examples/ansible/connection-plugin/2.6.x/packer.py
Packerテンプレート( JSON形式 )• Packerでどのようなマシンイメージを作成するかを定義したJSON形式のファイル– ファイル名は任意につけることができる(今回はpacker.json )– builders、description、min_packer_version、post-processors、provisioners、variables のセクションで細かく定義が可能• 必須セクションは builders のみで残りはオプション• 今回、特に重要なのが builders と provisioners– https://www.packer.io/docs/templates/index.html42
packer.json (1){"builders": [{"ami_description": "Windows 2016 AMI image created by Packer","ami_name": "packer-win2016-{{timestamp | clean_resource_name}}","iam_instance_profile": "packer-ec2-role","instance_type": "t3.medium","vpc_id": "vpc-XXXXXXXXXXXXXXX”,"subnet_id": "subnet-XXXXXXXXXX","region": "ap-northeast-1","type": "amazon-ebs","user_data_file": "win-userdata.txt","communicator": "winrm","winrm_username": "Administrator",43buildersセクションでは、作成するAMIに関する設定や、AMIの元となるEC2インスタンスに関係するパラメータを指定する。また、今回はWindowsを利⽤するので、コミュニケーターに「WinRM」を指定している。
紹介するファイル⼀覧https://github.com/tsukaman /jtf2019-packer-ansible-aws├ README.md├ ansible│ ├ after_reboot.yml│ ├ connection_plugins│ │ └ packer.py│ └ site.yml├ buildspec.yml├ files│ └ ansible.cfg[ 右へ続く ][ 左からの続き ]├ packer.json├ powershell│ ├ ConfigureRemotingForAnsible.ps1│ └ sysprep.ps1├ scripts│ ├ build.sh│ ├ run.sh│ └ validate.sh└ win-userdata.txt44• ConfigureRemotingForAnsible.ps1 の⼊⼿先https://github.com/ansible/ansible/blob/devel/examples/scripts/ConfigureRemotingForAnsible.ps1• packer.py の⼊⼿先https://github.com/hashicorp/packer/blob/master/examples/ansible/connection-plugin/2.6.x/packer.py
win-userdata.txtwinrm quickconfig -qwinrm set winrm/config/winrs '@{MaxMemoryPerShellMB="300"}'winrm set winrm/config '@{MaxTimeoutms="1800000"}'winrm set winrm/config/service '@{AllowUnencrypted="true"}'winrm set winrm/config/service/auth '@{Basic="true"}'netsh advfirewall firewall add rule name="WinRM 5985" protocol=TCP dir=inlocalport=5985 action=allownetsh advfirewall firewall add rule name="WinRM 5986" protocol=TCP dir=inlocalport=5986 action=allownet stop winrmsc config winrm start=autonet start winrmSet-ExecutionPolicy -ExecutionPolicy Bypass -Scope LocalMachine451⾏ずつで⼊⼒インスタンス起動時の実⾏スクリプト(PowerShell)で、WinRM通信が出来るように設定している。参考︓PackerでWindows Server 2016のAMIを作成してみたhttps://dev.classmethod.jp/cloud/aws/packer-winsrv2016-createami/
packer.json (2)"source_ami_filter": {"filters": {"virtualization-type": "hvm","name": "*Windows_Server-2016-Japanese-Full-Base-*","root-device-type": "ebs"},"owners": "amazon","most_recent": true},46カスタムAMIの元となるEC2インスタンスを、どのAMIから起動させるかの設定。今回は、Windows2016イメージで、上記の条件にマッチするもののうち、最新のものを選択するようにフィルタリングしている。
packer.json (3)"tags": {"Base_AMI_Name": "{{ .SourceAMIName }}","Extra": "{{ .SourceAMITags.TagName }}","Packer": "true","Release": "Latest"},"run_tags": {"Packer": "true"},"run_volume_tags": {"Packer": "true"},}],47作成されるAMIや、作成中のEC2インスタンスおよびEBSボリュームに設定されるTAG情報を指定している。カスタマイズAMIは元々どのAMIを元に作成されたかなどを情報として埋め込んでいる。
packer.json (4)"provisioners": [{"type": "ansible","playbook_file": "./ansible/site.yml","extra_arguments": ["--connection", "packer", "-v","--extra-vars", "ansible_shell_type=powershellansible_shell_executable=None","--vault-password-file={{user `vault_path`}}"]},481⾏で⼊⼒ここからProvisionerセクション。作成したEC2インスタンスへのカスタマイズとして、site.ymlのプレイブックを実⾏している。ansible実⾏時の引数なども柔軟に指定出来る。vault-password-fileは後ほど定義するユーザ変数を参照させている。
packer.json (5){"type": "powershell","inline": ["mkdir C:¥¥tmp"]},{"type": "powershell","inline": ["Import-Module -name AWSPowerShell","Copy-S3Object -BucketName バケット名 -Key ファイル名 -LocalFile C:¥¥tmp¥¥保存ファイル名"]},491⾏で⼊⼒powershell provisionerにより、EC2上でコマンドを実⾏させている。こちらの内容詳細は後述する。
packer.json (6){"type": "windows-restart","restart_check_command": "powershell -command ¥"& {Write-Output 'restarted.'}¥""},{"type": "ansible","playbook_file": "./ansible/after_reboot.yml","extra_arguments": ["--connection", "packer", "-v","--extra-vars", "ansible_shell_type=powershellansible_shell_executable=None","--vault-password-file={{user `vault_path`}}"]},501⾏で⼊⼒1⾏で⼊⼒windows-restart provisionerによりEC2インスタンスを再起動させている。また、再起動後にafter_reboot.ymlのプレイブックを実⾏させている。この部分の詳細は後述する。
packer.json (7){"type": "file","source": "powershell/ConfigureRemotingForAnsible.ps1","destination": "C:¥¥tmp¥¥ConfigureRemotingForAnsible.ps1"},{"type": "powershell","inline": ["C:¥¥tmp¥¥ConfigureRemotingForAnsible.ps1-SkipNetworkProfileChec -CertValidityDays 3650","rm C:¥¥tmp -Recurse"]},511⾏で⼊⼒HTTPS経由でAnsibleを実⾏させる為のセットアップスクリプトを配置して実⾏させている。また、このスクリプトが⾃動作成する⾃⼰署名証明書の有効期限を3650⽇に延⻑している。
packer.json (8){"type": "powershell","scripts": ["powershell/sysprep.ps1"]}],"variables": {"vault_path": "vault_password_file"}}52処理の最後にsysprepを実⾏させるPowerShellスクリプトをpowershellprovisionerで実⾏している。この部分では、前述のユーザ変数”vault-path”を定義している。
紹介するファイル⼀覧https://github.com/tsukaman /jtf2019-packer-ansible-aws├ README.md├ ansible│ ├ after_reboot.yml│ ├ connection_plugins│ │ └ packer.py│ └ site.yml├ buildspec.yml├ files│ └ ansible.cfg[ 右へ続く ][ 左からの続き ]├ packer.json├ powershell│ ├ ConfigureRemotingForAnsible.ps1│ └ sysprep.ps1├ scripts│ ├ build.sh│ ├ run.sh│ └ validate.sh└ win-userdata.txt53• ConfigureRemotingForAnsible.ps1 の⼊⼿先https://github.com/ansible/ansible/blob/devel/examples/scripts/ConfigureRemotingForAnsible.ps1• packer.py の⼊⼿先https://github.com/hashicorp/packer/blob/master/examples/ansible/connection-plugin/2.6.x/packer.py
sysprep.ps1C:¥ProgramData¥Amazon¥EC2-Windows¥Launch¥Scripts¥InitializeInstance.ps1 –ScheduleC:¥ProgramData¥Amazon¥EC2-Windows¥Launch¥Scripts¥SysprepInstance.ps1541⾏で⼊⼒1⾏で⼊⼒AWSで提供されるWindows2016 AMI内で⽤意されている、初期化スクリプトを実⾏している。参考︓Amazon EC2 Windows インスタンス⽤ユーザーガイド |Sysprep と EC2Launch の使⽤https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/WindowsGuide/ec2launch.html#ec2launch-sysprep
紹介するファイル⼀覧https://github.com/tsukaman /jtf2019-packer-ansible-aws├ README.md├ ansible│ ├ after_reboot.yml│ ├ connection_plugins│ │ └ packer.py│ └ site.yml├ buildspec.yml├ files│ └ ansible.cfg[ 右へ続く ][ 左からの続き ]├ packer.json├ powershell│ ├ ConfigureRemotingForAnsible.ps1│ └ sysprep.ps1├ scripts│ ├ build.sh│ ├ run.sh│ └ validate.sh└ win-userdata.txt55• ConfigureRemotingForAnsible.ps1 の⼊⼿先https://github.com/ansible/ansible/blob/devel/examples/scripts/ConfigureRemotingForAnsible.ps1• packer.py の⼊⼿先https://github.com/hashicorp/packer/blob/master/examples/ansible/connection-plugin/2.6.x/packer.py
site.yml (1)---- hosts: alltasks:- name: Ensure local user for ansible is presentwin_user:name: ansiblefullname: ansibledescription: 'Ansible⽤ユーザ'password: '@nsible01'password_never_expires: yesstate: presentgroups:- Administrators- name: Disable password expirartionwin_security_policy:section: System Accesskey: MaximumPasswordAgevalue: -156- name: Disable password complexity reqwin_security_policy:section: System Accesskey: PasswordComplexityvalue: 0- name: Set Allowed user for shutdownwin_user_right:name: SeShutdownPrivilegeusers:- Administratorsaction: set- name: Change power plan to high performancewin_power_plan:name: '⾼パフォーマンス'
site.yml (2)- name: Disable Windows Firewallwin_firewall:state: disabledprofiles:- Domain- Private- Public- name: Install SNMP servicewin_feature:name: SNMP-Serviceinclude_management_tools: yesinclude_sub_features: yesstate: present57
after_reboot.yml- hosts: alltasks:- name: Set startup mode to auto and ensure it is startedwin_service:name: SNMPstart_mode: autostate: started58SNMPサービスの起動設定は機能インストール後、⼀度再起動を経てからじゃないと設定できないので、別のプレイブックにタスクを記述し、再起動後に実⾏する
おもひで何 が 私 を 泣 か せ た の か59
Ansibleのバージョンが新しすぎる場合に死ぬ• Packer/Ansible Provisionerを使ってWindows2016のAMIを作成する場合、Ansible2.8を使うと謎のエラーで死ぬ– Windows2016以外でもダメかも知れない(未検証)– そのうち直ると思うけど、12⽉2⽇現在でIssueはOpenのまま– 2.7.10なら動くという報告がIssueのDiscussionスレッドにある• 私は何をしたか︖– Dockerイメージのベースであるansible-runnerのTAG指定• ansible-runner:1.3.4ではAnsibleは2.7.10• yum updateをウッカリかけると最新バージョンになるので注意– yum update -y --exclude=ʻansible*ʻ みたいにしよう60
Dockerfilehttps://github.com /tsukaman /jtf2019-packer-ansible-docker-imageFROM ansible/ansible-runner:1.3.4ENV PACKER_VERSION 1.4.5WORKDIR /usr/local/binRUN set -x && ¥yum install -y https://centos7.iuscommunity.org/ius-release.rpm && ¥yum update -y --exclude='ansible*' && ¥yum install -y jq python2-pip tree unzip wget && ¥rm -rf /var/cache/yum/* && yum clean all && ¥wget -q https://releases.hashicorp.com/packer/${PACKER_VERSION}/packer_${PACKER_VERSION}_linux_amd64.zip && ¥unzip ./packer_${PACKER_VERSION}_linux_amd64.zip && ¥rm ./packer_${PACKER_VERSION}_linux_amd64.zip && ¥pip install --upgrade pip && ¥pip install awscli boto pywinrm611⾏で⼊⼒
ファイル転送が死ぬほど遅いので死ぬ• WinRMを利⽤している場合、そもそもファイル転送速度が遅い– ⾮常に転送速度が遅いので⼤きなファイルの転送は避ける– Ansibleのwin_copyモジュールのドキュメントにも⾔及あり• 「Webサーバでホストし、ターゲットにダウンロードさせろ」– openSSHを使った通信も試験的に導⼊されたが私は未検証• 私は何をしたか︖– ⾃動処理の中でWebサーバを建てるという⾏為が微妙だった– AWS環境なのでS3 Bucketに巨⼤ファイルを置くことにした– ターゲットからはPowerShell for AWSでダウンロードさせる• S3にアクセスできるようにEC2 Roleの仕組みを使う62
packer.json (1){"builders": [{"ami_description": "Windows 2016 AMI image created by Packer","ami_name": "packer-win2016-{{timestamp | clean_resource_name}}","iam_instance_profile": "packer-ec2-role","instance_type": "t3.medium","vpc_id": "vpc-XXXXXXXXXXXXXXX”"subnet_id": "subnet-XXXXXXXXXX","region": "ap-northeast-1","type": "amazon-ebs","user_data_file": "win-userdata.txt","communicator": "winrm","winrm_username": "Administrator",63S3 バケットからファイルのダウンロードをさせる為に、特定のS3Bucket内のファイルを読み取ることができるRoleを作成し、EC2インスタンスに割り当てる。
Roleに割り当てるポリシー(例){"Version": "2012-10-17","Statement": [{"Sid": "","Effect": "Allow","Action": ["s3:List*","s3:Get*"],"Resource": ["arn:aws:s3:::バケット名/*","arn:aws:s3:::バケット名"]},64{"Sid": "","Effect": "Allow","Action": "s3:ListAllMyBuckets","Resource": "*"}]}Role作成時は、信頼するエンティティとしてEC2を選択し、権限ポリシーとしてこの内容を指定する。
packer.json (5){"type": "powershell","inline": ["mkdir C:¥¥tmp"]},{"type": "powershell","inline": ["Import-Module -name AWSPowerShell",“Copy-S3Object -BucketName バケット名 -Key ファイル名 -LocalFile C:¥¥tmp¥¥保存ファイル名"]},651⾏で⼊⼒ポリシーで許可したS3バケット内にダウンロードさせたいファイルを置き、それをEC2インスタンス内に保存させる。
win_rebootを使うとpackerの処理が死ぬ• カスタマイズ内容によっては再起動が必要なケースがある– サービスやアプリケーションのインストール、レジストリの変更など、再起動しないと反映されない項⽬がある– 新規サービスの起動設定をする場合、再起動が必要になった– Ansibleには再起動を⾏うModuleがあるが、安直に使うべからず• 再起動後にセッションが復帰せず、Packer処理がTimeoutする• 私は何をしたか︖– そもそもPackerに、インスタンスを再起動する為の仕組み(windows-restart provisioner)が⽤意されている– Ansibleにこだわりすぎないで、他の⼿段にも⽬を向ける• 特にPowerShellはWindowsではほぼ最強・・・。66
packer.json (6){"type": "windows-restart","restart_check_command": "powershell -command ¥"& {Write-Output 'restarted.'}¥""},{"type": "ansible","playbook_file": "./ansible/after_reboot.yml","extra_arguments": ["--connection", "packer", "-v","--extra-vars", "ansible_shell_type=powershellansible_shell_executable=None","--vault-password-file={{user `vault_path`}}"]},671⾏で⼊⼒1⾏で⼊⼒windows-restart provisionerによりEC2インスタンスを再起動させている。また、再起動後にafter_reboot.ymlのプレイブックを実⾏させている。
sysprepで初期化される項⽬がでて死ぬ• 作成するのはGolden ImageなのでSIDなどの初期化が必要– AWSのWindows AMIはsysprepを実⾏する仕組みが⽤意される– ただし、Sysprep実⾏により初期化される設定がある• ライセンス情報、Administratorユーザ情報、Networkアダプタ情報、Windows Firewall設定など– 尚、この件、調査してくれたのは同僚で私ではない・・・(ありがたや• 私は何をしたか︖– 巻き戻るものは仕⽅がないので、EC2インスタンス作成時または作成後にこれらの設定がされるようにした• user-dataでの設定と、ansible-playbook実⾏を併⽤• PackerでAnsibleを使うため、Ansibleの為の設定がほぼ出来ているという点はメリットと⾔える68
ほかにもこんな素敵♡な地獄がたくさん。• そもそも情報が少ない。– ⽇本語だけじゃなく英語も。• Windows Moduleが少ない。– 2.8で対応になったものもあるが・・・。• 結局PowerShell頼みになるケースも。– Ansibleを使う意味を⾒失いそうに。• レジストリ編集しか⽅法がないことも。– Ansibleを使う意m(ry• カスタマイズ指⽰がGUIベース。– 「チェックボックスを外す」「お、おう」• デバッグがつろい。原因 is どこ。– Packer?Ansible?CodeBuild?いいえケf(ry• ケチってインスタンスを低スペックで起動し死ぬ。– 特にメモリがしょぼいとすぐAnsibleがエラーに。• 私のWindows⼒、PowerShell⼒が低い。– Apple信者ゆえ・・・。ゆるして・・・。• ノリノリでJTFのCFPだしたけど仕事が⼤炎上– これは⾃業⾃得(なのかな・・・)69
ほかにもこんな素敵♡な地獄がたくさん。• そもそも情報が少ない。– ⽇本語だけじゃなく英語も。• Windows Moduleが少ない。– 2.8で対応になったものもあるが・・・。• 結局PowerShell頼みになるケースも。– Ansibleを使う意味を⾒失いそうに。• レジストリ編集しか⽅法がないことも。– Ansibleを使う意m(ry• カスタマイズ指⽰がGUIベース。– 「チェックボックスを外す」「お、おう」• デバッグがつろい。原因isどこ。– Packer?Ansible?CodeBuild?いいえケf(ry• 私のWindows⼒、PowerShell⼒が低い。– Apple信者ゆえ・・・。ゆるして・・・。• やってることが変態(ドM)すぎて仲間が居ない。– PR/Mergeを1⼈でやる意味(時間かかるんじゃ)70One More Thing...
あれ?もういらない…?
待て︕まだ慌てる時間じゃない︕• Packerのいいところ– AWS以外のイメージも作れるよ︕– ちまたに情報が結構あるよ(ただし悪魔合体させなければ)– Ansibleが使える = 学習コストが低い・・・かも︕– 使えるベースイメージも幅広く柔軟性が⾼い︕• EC2 Image Builderのいいところ– AWS公式ツールの安⼼感– マネージドサービスですぐ使える&基本無料– AWSサービスとの連携が充実(S3とかIAMとか)– 更新やテストなどの痒いところに⼿が届く機能も実装76
待て︕まだ慌てる時間じゃない︕• Packerのいいところ– AWS以外のイメージも作れるよ︕– ちまたに情報が結構あるよ(ただし悪魔合体させなければ)– Ansibleが使える = 学習コストが低い・・・かも︕– 使えるベースイメージも幅広く柔軟性が⾼い︕• EC2 Image Builderのいいところ– AWS公式ツールの安⼼感– マネージドサービスですぐ使える&基本無料– AWSサービスとの連携が充実(S3とかIAMとか)– 更新やテストなどの痒いところに⼿が届く機能も実装77選択肢を増やし状況に応じて使い分ける!
SH A RE!MYENGINEERINGCU LT U RE78ま と め
中 年 の主張そ れ で は お 聴 き く だ さ い79
ಛʹͳ͠ʂ80
ಛʹͳ͠ʂ81強いて言えば
͕ؒཉ͍͠ʂ82
͕ؒཉ͍͠ʂ83あと
ങͬͯͶʂ84
ങͬͯͶʂ85つまり
86
87さいごに
ϝΨω͍͍ͧʂ88
マジレスすると・・・• ⼤切にしたいと想っていること–しなやかさ• 変化をおそれず、柔軟に、しかし芯を持つ。–⾃分らしさ• 死ぬまで考え続けるべき永遠のテーマ。–おもしろさ• 迷ったときは⾯⽩そうな⽅へ。89
またな︕