下記のスクリプト群で実現してみました。
$ tree ./ ./ ├── ansible │ └── packer │ └── ansible-amazonlinux.yml ├── cloudformation │ └── packer.json ├── create-ami.sh └── packer └── ansible-amazonlinux.json
次のように実行することで、VPCが作成されたあとにPackerが、そのVPC内にEC2作って、
いろいろとインストールした後、EC2からAMIを作成してくれます。
./create-ami.sh
create-ami.sh
#!/bin/sh EXTRA_VARS=$(cat <必要な変数を設定して、AnsibleのPlaybookを実行しています。
リージョンの指定(自分がいるリージョンを取得)は
“AWS CLI”で最新の”Amazon Linux AMI”(gp2)のIDを取得する
で紹介したものを使っています。ansible-amazonlinux.yml
- hosts: localhost gather_facts: no connection: local tasks: - name: cloudformation cloudformation: state: present region: "{{ Region }}" template: ../../cloudformation/packer.json stack_name: Packer register: cloudformation - name: epoch shell: date +%s register: epoch - name: get amazonlinux ami shell: > aws ec2 describe-images --region {{ Region }} --owners amazon --filters "Name=name,Values=amzn-ami-hvm-*-gp2" --query 'reverse(sort_by(Images,&CreationDate))[0].ImageId' --output text register: amazonlinux_image_id - name: packer shell: > packer build -var 'Region={{ Region }}' -var 'VpcId={{ cloudformation.stack_outputs.Vpc }}' -var 'SubnetId={{ cloudformation.stack_outputs.Subnet }}' -var 'Name={{ Name }}' -var 'Epoch={{ epoch.stdout }}' -var 'SourceAmi={{ amazonlinux_image_id.stdout }}' ../../packer/ansible-amazonlinux.json最初にCloudFormationでVPCを作っています。
理由としては、僕が扱ってるアカウントがEC2-Classicが使えたり使えなかったり、
デフォルトVPCがあったり無かったり、だったので、
どこでも同じように利用できるためにPacker用のVPCを、まず作ることにしました。最初は”AWS CLI”で作ってたんですが、CloudFromationが作成し終わってから、
次の処理を実施する場合、別途CloudFormationの状態チェックを行う処理(ループ)を
作り込む必要があり、それが面倒だったのでAnsibleの利用に切替ました。上記のPlaybookは、CloudFormationの構築が完了した後に、次のタスクが実行されるので、
状態チェックのループを作り込む必要はありません。
また既にCloudFormationのStackがある場合、テンプレートの修正があった場合は
勝手にUpdateになり、ない場合はスキップもしてくれるので、その辺も楽でした。
(これが噂の冪等性ってやつですね!)そして、下記で紹介した方法で最新の”Amazon Linux AMI”(gp2)のIDを取得して、
“AWS CLI”で最新の”Amazon Linux AMI”(gp2)のIDを取得する
最後に、VPCやらAMIやらの情報をパラメータとしてPackerに渡してAMIを作成しています。packer.json
{ "AWSTemplateFormatVersion": "2010-09-09", "Parameters": { "VpcCidrBlock": { "Type": "String", "Default": "10.0.0.0/16" } }, "Resources": { "Vpc": { "Type": "AWS::EC2::VPC", "Properties": { "CidrBlock": { "Ref": "VpcCidrBlock" }, "EnableDnsSupport": "true", "EnableDnsHostnames": "true", "InstanceTenancy": "default", "Tags": [ { "Key": "Name", "Value": "Packer" } ] } }, "InternetGateway": { "Type": "AWS::EC2::InternetGateway", "Properties": { "Tags": [ { "Key": "Name", "Value": "Packer" } ] } }, "VpcGatewayAttachment": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { "VpcId": { "Ref": "Vpc" }, "InternetGatewayId": { "Ref": "InternetGateway" } } }, "RouteTable": { "Type": "AWS::EC2::RouteTable", "Properties": { "VpcId": { "Ref": "Vpc" }, "Tags": [ { "Key": "Name", "Value": "Packer" } ] } }, "Route" : { "Type": "AWS::EC2::Route", "Properties": { "RouteTableId": { "Ref": "RouteTable" }, "DestinationCidrBlock": "0.0.0.0/0", "GatewayId": { "Ref": "InternetGateway" } } }, "Subnet" : { "Type": "AWS::EC2::Subnet", "Properties": { "VpcId": { "Ref": "Vpc" }, "CidrBlock": { "Ref": "VpcCidrBlock" }, "AvailabilityZone": { "Fn::Select": [ "0", { "Fn::GetAZs": { "Ref": "AWS::Region" } } ] }, "Tags": [ { "Key": "Name", "Value": "Packer" } ] } }, "SubnetRouteTableAssociation": { "Type": "AWS::EC2::SubnetRouteTableAssociation", "Properties": { "SubnetId": { "Ref": "Subnet" }, "RouteTableId": { "Ref": "RouteTable" } } } }, "Outputs": { "Vpc": { "Value": { "Ref": "Vpc" } }, "Subnet": { "Value": { "Ref": "Subnet" } } } }こんな感じのVPCを作ってます。
Packerは、このパブリックサブネットの中にEC2を起動します。ansible-amazonlinux.json
{ "variables": { "Region": "", "VpcId": "", "SubnetId": "", "Name": "", "Epoch": "", "SourceAmi": "" }, "builders": [ { "type": "amazon-ebs", "region": "{{user `Region`}}", "source_ami": "{{user `SourceAmi`}}", "instance_type": "t2.micro", "ssh_username": "ec2-user", "vpc_id": "{{user `VpcId`}}", "subnet_id": "{{user `SubnetId`}}", "associate_public_ip_address": "true", "enhanced_networking": "true", "ami_name": "{{user `Name`}}_{{user `Epoch`}}" } ], "provisioners": [ { "type": "shell", "inline": [ "sudo yum -y update", "sudo pip install ansible", "sudo mkdir /etc/ansible", "sudo touch /etc/ansible/hosts", "rm -f /home/ec2-user/.ssh/authorized_keys" ] } ] }パラメータで渡ってきたVPCやAMIの情報を使ってAMIを作成しています。
“Shell Provisioner”で”Ansible (Local) Provisioner”が利用できる環境を作ってます。無事、実行されると、下記のようにAMIが作成されてます。
元記事はこちら