之前有寫過一篇 一條龍佈署 CI/CD 從 Travis 到 CodeDeploy 的 On-Premises (IAM Role/STS) 的作法,對於 On-Premises 來說集中控管便於管理,而 AWS CodeDeploy 的另一個方式 IAM User 讓每一個 On-Premises Server 都擁有不同的 IAM User key 來訪問,這個作法我覺得有好有壞,
好在於你的 Key 要是不小心掉了,可以快速知道是哪一台發生問題,且不會所有 On-Premises 都淪陷
壞在於你的 IAM User 會多到爆炸 ..
關係架構圖:
與使用 IAM Role/STS 不同的地方在於直接用 IAM User 訪問,而不再需要用 STS 交換 token 後用再 Assume Role 了
環境
- Region(東京) = ap-northeast-1
- 產品名稱 = project
在進行 CodeDeploy On-Premises 之前必須先確認你的網路環境允許連上以下 AWS 服務
- S3 (每一個 S3 bucket 都是全球唯一的位址)
- ${bucketname}.s3-${region}.amazonaws.com
- CodeDeploy Server
- codedeploy.${region}.amazonaws.com
- AWSCLI 安裝
- s3.amazonaws.com
- CodeDeploy Agent 安裝
- aws-codedeploy-us-east-1.s3.amazonaws.com (非 EC2 的 fail-safe mode 安裝位置)
- aws-codedeploy-${region}.s3.amazonaws.com
- codedeploy-commands.${region}.amazonaws.com
必要條件
用來建立以下服務的 IAM User 必須擁有以下權限
Attach
AWSCodeDeployFullAccess
lnline
iam:CreateAccessKey,
iam:CreateUser,
iam:DeleteAccessKey,
iam:DeleteUser,
iam:DeleteUserPolicy,
iam:ListAccessKeys,
iam:ListUserPolicies,
iam:PutUserPolicy,
iam:GetUser
此安裝將會建立以下 AWS 服務
- 一個 S3 bucket
- 一個 IAM User 給 Travis CI 使用 CodeDeploy, S3
- 一個 IAM User 給 On-Premises 使用 CodeDeploy, S3 服務使用
- 一個 IAM Role 給 CodeDeploy 服務使用
- 一個 CodeDeploy Application 與 deployment_group
- 在 CodeDeploy 註冊 On-Premises (register-on-premises-instance)
全程將使用 AWS command line 建立,將不會有 Web cosole 的執行過程
開始建立 CodeDeploy On-Premises (IAM User)
或者你可以用 shazi7804/codedeploy-permissions-onpremises 進行自動佈署。
Step 1: 建立 S3 bucket
$ aws s3api create-bucket --bucket codedeploy-project --region ap-northeast-1 --create-bucket-configuration LocationConstraint=ap-northeast-1
強者同事補充:根據 AWS-CLI 的 Help 指出,要在 eu-west-1 之外的 region 建 bucket,需要加上 LocationConstraint 參數。
確認可以訪問
$ aws s3 ls project
Step 2: 建立 IAM User for Travis CI
建立 IAM User
$ aws iam create-user --user-name travisci-project
Attach Policy – AWSCodeDeployDeployerAccess
$ aws iam attach-user-policy --user-name travisci-project --policy-arn arn:aws:iam::aws:policy/AWSCodeDeployDeployerAccess
lnline Policy – 授與 bucket name 為 codedeploy-project 有權限
$ tee travisci-project-lnline.json <<EOF { "Version": "2012-10-17", "Statement": [ { "Sid": "Stmt1487528506000", "Effect": "Allow", "Action": [ "s3:*" ], "Resource": [ "arn:aws:s3:::codedeploy-project/*" ] } ] } EOF $ aws iam put-user-policy --user-name travis-project --policy-name s3-travisci-project --policy-document file://travisci-project-lnline.json $ rm travisci-project-lnline.json
Step 3: 建立 IAM User for On-Premises
每一個 On-Premises 皆使用獨立的 IAM User,這邊示範建立 dev
$ aws iam create-user --user-name codedeploy-onpremises-project-dev
lnline IamPolicyfile.json
{ "Version": "2012-10-17", "Statement": [ { "Action": [ "s3:GetObject", "s3:GetObjectVersion", "s3:ListBucket" ], "Effect": "Allow", "Resource": "arn:aws:s3:::codedeploy-project/*" } ] } $ aws iam put-user-policy --user-name codedeploy-onpremises-project-dev --policy-name iam-codedeploy-project-onpremises --policy-document file://IamPolicyfile.json.json $ rm IamPolicyfile.json
Step 4: 建立 IAM Role for CodeDeploy
給 CodeDeploy Server 的 IAM Role 一個 AWS account 僅需要一個。
$ tee role-codedeploy-trust.json <<EOF { "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "codedeploy.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF $ aws iam create-role --role-name Role-CodeDeploy --assume-role-policy-document file://role-codedeploy-trust.json $ rm role-codedeploy-trust.json
Attach policy
$ aws iam attach-role-policy --role-name Role-CodeDeploy --policy-arn arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole
Create Profile
$ aws iam create-instance-profile --instance-profile-name Role_CodeDeploy-Profile
把 Role 和 Profile 關聯起來
$ aws iam add-role-to-instance-profile --role-name Role-CodeDeploy --instance-profile-name Role_CodeDeploy-Profile
Step 5: 建立 CodeDeploy
Create application
$ aws deploy create-application --application-name project --region ap-northeast-1
Create deployment_group (prod)
$ aws deploy create-deployment-group \ --application-name project \ --deployment-config-name CodeDeployDefault.AllAtOnce \ --deployment-group-name prod \ --service-role-arn arn:aws:iam::0123456789:role/Role-CodeDeploy \ --region ap-northeast-1
Step 6: 註冊 CodeDeploy On-Premises
註冊 On-Premises instance
$ aws deploy register-on-premises-instance --instance-name project-dev --iam-user-arn arn:aws:iam::0123456789:user/codedeploy-onpremises-project-dev
替註冊的 On-Premises instance 加入 tags:Key=Name,Values=project-dev
$ aws deploy add-tags-to-on-premises-instances --instance-names project-dev --tags Key=Name,Values=project-dev
在 On-Premises Server 安裝 CodeDeploy
Step 1: 設定 Proxy
如果你的 On-Premises 不允許直接訪問外部網路,需要另外設定 Proxy,因為安裝 CodeDeploy 必須對外訪問。
建議先把他寫到 /etc/environment,否則在接下來的 sudo 會無法使用 export 環境變數
Step 2: 安裝 aws cli
$ sudo apt-get install -y wget unzip $ cd /tmp $ wget https://s3.amazonaws.com/aws-cli/awscli-bundle.zip $ unzip awscli-bundle.zip $ cd awscli-bundle $ sudo chmod +x install $ sudo ./install -i /usr/local/aws -b /usr/local/bin/aws
確認版本為最新的 aws cli
$ aws --version
在 On-Premises 必須取得 #Step 3: “建立 IAM User for On-Premises” 的 Access Key/ Secret Access Key,並且登記在 On-Premises Server 的 aws cli
$ aws configure
Step 3: 安裝 CodeDeploy agent
$ sudo apt-get install -y ruby $ wget https://aws-codedeploy-ap-northeast-1.s3.amazonaws.com/latest/install $ sudo chmod +x install $ sudo ./install auto
install 有支援 proxy 參數,可以用 –proxy 解決
Step 4: 設定檔 codedeploy.onpremises.yml & codedeployagent.yml
建立 CodeDeploy On-Premises 需要使用的設定檔
$ sudo tee /etc/codedeploy-agent/conf/codedeploy.onpremises.yml <<EOF --- aws_access_key_id: OnPremises IAM User 的 access key aws_secret_access_key: OnPremises IAM User 的 secret key iam_user_arn: arn:aws:iam::0123456789:user/codedeploy-project-onpremises-dev region: ap-northeast-1 EOF
- iam_session_arn 是在 #Step 6: “建立 CodeDeploy” 中建立的 sts session arn
- aws_credentials_file 是要用來放 sts session 的 token and access key
- region 為你 codedeploy 的所在地區
在 codedeployagent.yml 把 proxy 參數加入,讓 codedeploy agent 可以用 proxy 去更新
:proxy_uri: http://proxy.com:3128
重新啟動 CodeDeploy agent 把 proxy 的設定參數吃進去
$ sudo service codedeploy-agent restart
在 CodeDeploy 中決定 deploy 的 On-Premises instance tags
CodeDeploy 中的 deployment_group tags 必須和 On-Premises instance tags 符合才會進行 CodeDeploy。
你可以透過 Web cosole 在 CodeDeploy/Application/deployment_group/Search by tags 進行設定 tags,tags type 必須是 On-premises-instance
或是使用 awscli “更新” tags,此設定會直接覆蓋現有 tags,若有多筆 tags 可以用 json 或是多個 –on-premises-instance-tag-filters 來指定 tag
$ aws deploy update-deployment-group \ --application-name project \ --current-deployment-group-name master \ --on-premises-instance-tag-filters Key=Name,Value=project-dev,Type=KEY_AND_VALUE
或是用 json 更新 tags
$ tee multi_tags.json <<EOF [ { "Key": "project", "Value": "dev", "Type": "KEY_AND_VALUE" }, { "Key": "project", "Value": "staging", "Type": "KEY_AND_VALUE" } ] EOF $ aws deploy update-deployment-group \ --application-name project \ --current-deployment-group-name master \ --on-premises-instance-tag-filters file://multi_tags.json
驗證
驗證服務正在使用
$ ps ax | grep codedeploy codedeploy-agent: master 19248 codedeploy-agent: InstanceAgent::Plugins::CodeDeployPlugin::CommandPoller of master 19248
正常運作時 access codedeploy 的 log。
$ less /var/log/aws/codedeploy-agent/codedeploy-agent.log 2017-03-06 00:03:13 INFO [codedeploy-agent(19252)]: Version file found in /opt/codedeploy-agent/.version. 2017-03-06 00:04:14 INFO [codedeploy-agent(19252)]: [Aws::CodeDeployCommand::Client 200 61.019261 0 retries] poll_host_command(host_identifier:"arn:aws:sts::0123456789:assumed-role/Role-onpremises/project-session-server01")
收到 codedeploy 的 access log 狀態為 200
[codedeploy-agent(...)]: [Aws::CodeDeployCommand::Client 200 ....
Note
- 已 register 的 On-Premises,如果要 deregister 必須等待 24H 後才會消除,一樣的 instance name 無法重複申請
- CodeDeploy 的 On-Premises 方式不支援 Auto Scaling。
- CodeDeploy 的 deploy tags 方式不支援 * 等字符,必須完整輸入 tag name。
Reference