2018年7月、東京リージョンにFargateがやってきます。
Fargate導入に向け、既存のECS向けに作った資産は極力Fargateで動かす方針です。
テンポラリなジョブはすべてAWS Batchで実行する予定です。
AWS Batchの土台となるEC2には定期的に最新のAMIを自動で適用して、その流れでproxy設定もAMIに仕込む。という作業もAWS Batchでさせるつもりなので、そのためのBatchを紹介します。
Dockerfile
元となるジョブ定義に使用するコンテナイメージを作成するためのDockerfileです。
Dockerfile
FROM alpine:3.6
RUN apk update \
&& apk upgrade \
&& apk add --no-cache \
python \
bash \
curl \
&& apk add --no-cache --virtual .build-deps \
wget \
curl \
py-pip \
unzip \
&& wget --no-check-certificate -O /tmp/packer.zip https://releases.hashicorp.com/packer/1.2.4/packer_1.2.4_linux_amd64.zip \
&& unzip /tmp/packer.zip -d /usr/local/bin \
&& curl -o /bin/jq -L https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64 \
&& chmod +x /bin/jq \
&& pip install awscli \
&& apk add tzdata \
&& cp -p /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
&& apk del tzdata \
&& apk del .build-deps \
&& rm -rf /var/cache/apk/* \
&& rm -rf /tmp/* /var/tmp/*
COPY packer.sh /bin/
RUN chmod +x /bin/packer.sh
COPY packerfile.org /
CMD packer.sh
packerテンプレート
現時点(18/7/12)において、HTTPプロキシ設定では/etc/sysconfig/dockerに対するNO_PROXY 設定は 169.254.169.254だけとなっておりますが、169.254.170.2,/var/run/docker.sockが描き漏れています。(/var/run/docker.sockは不要かもしれません)
私の地道な布教の甲斐あって、現時点19/8/12では修正されてなされておられますご様子です。
packerfile.org
{
"builders":
[
{
"type": "amazon-ebs",
"ami_name": "{{%ENV%}}-{{%SOURCE_AMI%}}-{{%AMI_NAME}}",
"region": "ap-northeast-1",
"source_ami": "{{%SOURCE_AMI_ID%}}",
"instance_type": "m4.large",
"security_group_id": "{{%SECURITY_GROUP_ID%}}",
"subnet_id": "{{%SUBNET_ID%}}",
"ssh_timeout": "1m",
"ssh_username": "ec2-user",
"tags": {
"base-ami": "{{%SOURCE_AMI_ID%}}"
}
}
],
"provisioners": [
{
"type": "shell",
"execute_command": "{{ .Vars }} sudo -E sh '{{ .Path }}'",
"inline": [
"sudo echo 'http_proxy={{%HTTP_PROXY%}}' >> /etc/ecs/ecs.config ",
"sudo echo 'https_proxy={{%HTTPS_PROXY%}}' >> /etc/ecs/ecs.config ",
"sudo echo 'no_proxy=169.254.169.254,169.254.170.2,/var/run/docker.sock' >> /etc/ecs/ecs.config ",
"sudo echo 'env http_proxy={{%HTTP_PROXY%}}' >> /etc/init/ecs.override ",
"sudo echo 'env https_proxy={{%HTTPS_PROXY%}}' >> /etc/init/ecs.override ",
"sudo echo 'env no_proxy=169.254.169.254,169.254.170.2,/var/run/docker.sock' >> /etc/init/ecs.override ",
"sudo echo 'export http_proxy={{%HTTP_PROXY%}}' >> /etc/sysconfig/docker ",
"sudo echo 'export https_proxy={{%HTTPS_PROXY%}}' >> /etc/sysconfig/docker ",
"sudo echo 'export no_proxy=169.254.169.254,169.254.170.2' >> /etc/sysconfig/docker "
]
}
]
}
AMI入れ替えスクリプト
コンテナ内で実行する、AMI入れ替え作業をする元となるシェルスクリプトです。
一般的には、AWS Batchで実行するジョブの本体はs3等に置いておいて、Batch実行時にs3に取得しに行く流れみたいですが、コードの管理はgitLabでしっかりして、デプロイまでの流れは自動化するので大丈夫です。
packer.sh
#!/bin/bash
#####################
# ジョブ定義側で以下環境変数を設定する。
AMI_NAME=
BASE_COMPUTE_ENVIRONMENT=
HTTP_PROXY=
HTTPS_PROXY=
SECURITY_GROUP_IDS=
SUBNET_ID=
ENV=
YYYYMMDD=`date '+%Y%m%d%H%M'`
delete_batch_compute_environment()
{
COMPUTE_ENVIRONMENT_ARN=$1
COUNT=0
LOOP_COUNT=10
while [ ${COUNT} -lt ${LOOP_COUNT} -a "${STATE}" != "DISABLED" ]; do
# 既存のコンピューティング環境をDISABLE
aws batch update-compute-environment --compute-environment ${COMPUTE_ENVIRONMENT_ARN} --state DISABLED
STATE=`aws batch describe-compute-environments \
| jq '.computeEnvironments[]| select(.computeEnvironmentArn == "'${COMPUTE_ENVIRONMENT_ARN}'")|.state ' -r`
let COUNT++
done
if [ ${COUNT} -lt ${LOOP_COUNT} ];then
# DISABLEDになってもすぐに削除できないので3秒wait
sleep 3
aws batch delete-compute-environment --compute-environment ${COMPUTE_ENVIRONMENT_ARN}
else
echo "computing environment is not DISABLED"
exit 1
fi
}
# regionの設定
aws configure set default.region ap-northeast-1
# 最新のオプティマイズAMI名を取得
aws ssm get-parameters --names /aws/service/ecs/optimized-ami/amazon-linux/recommended > ssm_get_parameters.org
# 最新のオプティマイズAMI名を取得
SOURCE_AMI=`cat /ssm_get_parameters.org | jq .Parameters[0].Value -r | jq .image_name -r`
SOURCE_AMI_ID=`cat /ssm_get_parameters.org | jq .Parameters[0].Value -r | jq .image_id -r`
echo "#### base ami: ${SOURCE_AMI} ####"
# packer設定ファイル作成
cat packerfile.org | sed -e "s/{{%AMI_NAME%}}/${AMI_NAME}/g" \
-e "s/{{%SOURCE_AMI%}}/${SOURCE_AMI}/g" \
-e "s/{{%SOURCE_AMI_ID%}}/${SOURCE_AMI_ID}/g" \
-e "s/{{%HTTP_PROXY%}}/${HTTP_PROXY}/g" \
-e "s/{{%HTTPS_PROXY%}}/${HTTPS_PROXY}/g" \
-e "s/{{%SECURITY_GROUP_ID%}}/${SECURITY_GROUP_ID}/g" \
-e "s/{{%SUBNET_ID%}}/${SUBNET_ID}/g" \
-e "s/{{%ENV%}}/${ENV}/g" \
> /packerfile.json
echo "#### packerfile.json ####"
cat /packerfile.json
# optimized AMIを作成
LATEST_SOURCE_AMI_ID=`packer build /packerfile.json | tee output.log | tail -2 | head -2 \
| awk 'match($0, /ami-.*/) { print substr($0, RSTART, RLENGTH) }'`
if [ "${LATEST_SOURCE_AMI_ID}" == "" ]; then
echo "#### output.log ####"
cat /output.log
exit 0
fi
echo "#### optimized ami: ${LATEST_SOURCE_AMI_ID} ####"
# 最新のオプティマイズAMIから作成したAMIが登録されていないか確認する
# 仕様として、tagにbase-ami $SOURCE_AMI を含むことを記す
LIST_RECENT_SOURCE_AMI_ID=`aws ec2 describe-images --filters Name=tag-key,Values=base-ami,Name=tag-value,Values=${SOURCE_AMI_ID} \
| jq .Images[].ImageId -r`
for RECENT_SOURCE_AMI_ID in ${LIST_RECENT_SOURCE_AMI_ID}; do
LIST_COMPUTE_ENVIRONMENT_ARN+="`aws batch describe-compute-environments \
| jq '.computeEnvironments[] | select(.computeResources.imageId == "'${RECENT_SOURCE_AMI_ID}'") | .computeEnvironmentArn' -r` "
done
for OLD_COMPUTE_ENVIRONMENT_ARN in ${LIST_COMPUTE_ENVIRONMENT_ARN} ; do
# 新規コンピューティング環境の名称
NEW_COMPUTE_ENVIRONMENT=${BASE_COMPUTE_ENVIRONMENT}-${YYYYMMDD}
# 最近(RECENT) のAMIを使用したコンピューティング環境の設定ファイルを作成する
# 元の環境のstate が ENABLEDでないとあとで失敗する
aws batch describe-compute-environments \
| jq '.computeEnvironments[] | select(.computeEnvironmentArn == "'${OLD_COMPUTE_ENVIRONMENT_ARN}'")| {computeEnvironmentName,type,state,computeResources,serviceRole}' \
> /compute_environment.org
echo "#### compute_environment.org ####"
cat /compute_environment.org
# 最新(LATEST) のAMIを使用したコンピューティング環境の設定ファイルを作成する
cat compute_environment.org | sed -e "s/\"imageId\": \".*\"/\"imageId\": \"${LATEST_SOURCE_AMI_ID}\"/g" \
-e "s/\"computeEnvironmentName\": \".*\"/\"computeEnvironmentName\": \"${NEW_COMPUTE_ENVIRONMENT}\"/g" \
> /compute_environment.json
echo "#### compute_environment.json ####"
cat /compute_environment.json
echo "#### create job environment:${NEW_COMPUTE_ENVIRONMENT} ####"
NEW_COMPUTE_ENVIRONMENT_ARN=`aws batch create-compute-environment \
--cli-input-json file://compute_environment.json | jq '.computeEnvironmentArn' -r`
LIST_JOB_QUE=`aws batch describe-job-queues \
| jq '.jobQueues | map(select(.computeEnvironmentOrder[].computeEnvironment=="'${OLD_COMPUTE_ENVIRONMENT_ARN}'")) | .[].jobQueueArn' -r`
for JOB_QUE in ${LIST_JOB_QUE} ; do
# job queueのstatusをupdateするために、ジョブに登録されている環境とorder を取得する
LIST_JOB_QUE_COMPUTE_ENV=(`aws batch describe-job-queues --job-queues ${JOB_QUE}\
| jq '.jobQueues[].computeEnvironmentOrder[].computeEnvironment' -r`)
LIST_JOB_QUE_ORDER=(`aws batch describe-job-queues --job-queues ${JOB_QUE}\
| jq '.jobQueues[].computeEnvironmentOrder[].order' -r`)
UPDATE_LIST=""
# ジョブが登録されている環境のうち、古いコンピューティング環境を新しいものと置き換える
for ((i=0; i < ${#LIST_JOB_QUE_COMPUTE_ENV[@]}; i++)) ;do
if [ ${LIST_JOB_QUE_COMPUTE_ENV[i]} = ${OLD_COMPUTE_ENVIRONMENT_ARN} ]; then
UPDATE_LIST+="order=${LIST_JOB_QUE_ORDER[i]},computeEnvironment=${NEW_COMPUTE_ENVIRONMENT_ARN} "
else
UPDATE_LIST+="order=${LIST_JOB_QUE_ORDER[i]},computeEnvironment=${LIST_JOB_QUE_COMPUTE_ENV[i]} "
fi
done
echo "#### register job queue: ${JOB_QUE} ####"
# ジョブ再登録
aws batch update-job-queue --job-queue ${JOB_QUE} --compute-environment-order ${UPDATE_LIST}
done
echo "#### delete old compute environment: ${OLD_COMPUTE_ENVIRONMENT_ARN} ####"
# コンピューティング環境の削除
delete_batch_compute_environment ${OLD_COMPUTE_ENVIRONMENT_ARN}
done
exit 0