用CodeDeploy來做部署、更新和回退

一、準備工作和先決條件

(1)被部署的實例,需要安裝codedeploy-agent,安裝方法

git clone https://github.com/aws/aws-codedeploy-agent.git
cd aws-codedeploy-agent/bin
./install auto

或者用我從安裝過程中截獲的rpm包安裝也行,分享給大家wget即可
http://cypay-filesharing.s3.amazonaws.com/public/wangfei/codedeploy-agent-1.0-1.643.noarch.rpm
(2)創建一個存放代碼包的S3 bucket,此例中叫s3://CYPayCodeDeployBucket,美東地區
(3)創建一個Instance Profile,並使新創建的EC2實例使用該Instance Profile,這個過程中還需要創建個IAM Role,並讓Role與Profile關聯,該過程授權EC2實例內部的CodeDeploy-Agent能從S3下載版本包。然後再創建一個Service Role給Codedeploy服務用,該服務需要一些EC2權限

大概創建過程:創建個IAM Role,授權AssumeRole和訪問版本存放S3,再創建個Instance Profile,然後將之前的Role關聯到Profile上;再創建個Role給CodeDeploy服務用;
具體過程:
創建文件 CodeDeployInstanceProfile-Trust.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

再創建一個文件CodeDeployInstanceProfile-Permissions.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "s3:Get*",
        "s3:List*"
      ],
      "Effect": "Allow",
      "Resource":"arn:aws:s3:::CYPayCodeDeployBucket/*"
    }
  ]
}

然後創建角色叫CodeDeployInstanceRole,並給Role加策略

aws iam create-role \
    --role-name CodeDeployInstanceRole \
    --assume-role-policy-document file://CodeDeployInstanceProfile-Trust.json
aws iam put-role-policy \
    --role-name CodeDeployInstanceRole \
    --policy-name CDInstanceRole-Permissions \
    --policy-document file://CodeDeployInstanceProfile-Permissions.json

然後創建instance profile,並把剛纔創建的Role附加到instance profile上,這樣使用這個instance profile創建的EC2實例,就擁有Role對應的權限和策略

aws iam create-instance-profile \
    --instance-profile-name CodeDeployInstanceProfile
aws iam add-role-to-instance-profile \
    --instance-profile-name CodeDeployInstanceProfile \
    --role-name CodeDeployInstanceRole

至此,一個具有codedeploy相關權限的Instance Profile就創建好了,創建自動部署的EC2實例的時候需要使用該Profile

接下來創建一個Service Role 這個是codedeploy服務用來在EC2實例中部署代碼的
創建文件 CodeDeployServiceRole-Trust.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": [
            "codedeploy.us-east-1.amazonaws.com",
            "codedeploy.us-west-2.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

再創建一個文件CodeDeployServiceRole-Permissions.json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "autoscaling:PutLifecycleHook",
        "autoscaling:DeleteLifecycleHook",
        "autoscaling:RecordLifecycleActionHeartbeat",
        "autoscaling:CompleteLifecycleAction",
        "autoscaling:DescribeAutoscalingGroups",
        "autoscaling:PutInstanceInStandby",
        "autoscaling:PutInstanceInService",
        "ec2:Describe*"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}

創建一個角色CodeDeployServiceRole,然後將角色策略與角色相關聯

aws iam create-role \
    --role-name CodeDeployServiceRole \
    --assume-role-policy-document file://CodeDeployServiceRole-Trust.json
aws iam put-role-policy \
    --role-name CodeDeployServiceRole \
    --policy-name CDServiceRole-Permissions \
    --policy-document file://CodeDeployServiceRole-Permissions.json

獲取Role的相關信息,複製下來備用

aws iam get-role --role-name CodeDeployServiceRole --query "Role.Arn" --output text
arn:aws:iam::154xxxxx7698:role/CodeDeployServiceRole # mark this down

第(3)步總結:
創建兩個Role
CodeDeployInstanceRole
CodeDeployServiceRole
創建一個InstanceProfile
CodeDeployInstanceProfile
注意事項:
Instance Profile必須創建實例的時候選擇,事後暫無辦法讓沒選InstanceProfile的實例使用某個Profile
CodeDeploy-agent目前只在最新版的Amazon Linux,Ubuntu,Windows 上測試過,而且自帶yum源中沒有

二、用CodeDeploy部署個新項目
(1)上一步已經創建好使用CodeDeployInstanceProfile這個Profile的EC2實例,並且打好標籤的(例如Name=cms.front),而且實例上已經裝好了codedeploy-agent
(2)準備代碼,此處用tomcat應用舉例。
解壓代碼,在工程目錄目錄裏添加scripts目錄和一個appspec.yml,例如下面這樣的目錄結構,scripts裏面放部署時使用的腳本,appspec.yml文件定義代碼部署到哪個,用什麼用戶在什麼階段執行什麼腳本

cms.front/
├── appspec.yml
├── css/
├── error.jsp
├── fonts/
├── html/
├── images/
├── index.jsp
├── js/
├── META-INF/
├── scripts/
├── static/
└── WEB-INF/

appspec.yml文件內容,格式要求非常嚴格,不允許多餘空白

version: 0.0
os: linux
files:
  - source: /
    destination: /home/ec2-user/tomcat/webapps/
hooks:
  BeforeInstall:
    - location: scripts/check_dependencies.sh
      timeout: 300
      runas: root
  AfterInstall:
    - location: scripts/change_permissions.sh
      timeout: 300
      runas: root
  ApplicationStart:
    - location: scripts/start_server.sh
      timeout: 300
      runas: ec2-user
  ApplicationStop:
    - location: scripts/stop_server.sh
      timeout: 300
      runas: ec2-user

首次部署,需要安裝依賴軟件和環境,之後做代碼更新時就不需要了
可以把啓動腳本寫成重啓腳本
這四個腳本我就不多說了,自定義性比較強
然後重新打包,只包含內容,不要將上級目錄也打進包
cd ~/version/cms.front/ && zip -r cms.front.v1.0.zip *
然後將版本包上傳到上述創建的Bucket裏CYPayCodeDeployBucket
官方文檔中介紹用aws deploy push上傳,但是報錯了,也沒找到解決辦法,就用aws s3 cp上傳的
Missing required parameter in input: "UploadId"
Unknown parameter in input: "uploadId", must be one of: Bucket, Key, UploadId

更新aws-cli也無用,有解決此錯誤的請告訴我
然後創建一個Application,理解成一個具有相同功能的一個代碼工程,此例爲cms.front

aws deploy create-application --application-name CMSTomcatApplication

然後將重新打包好的版本包push到S3上(這步報錯了,所以手動傳的)

aws deploy push \
  --application-name CMSTomcatApplication \
  --s3-location s3://CYPayCodeDeployBucket/cms.front.v1.0.zip \
  --ignore-hidden-files

然後創建DeploymentGroup,理解成一組需要被部署相同代碼的EC2實例,此例爲cms.tomcat,按Tag來區分,或則按autoscal組來區分

aws deploy create-deployment-group \
  --application-name CMSTomcatApplication \
  --deployment-group-name CMSTomcatApplication \
  --deployment-config-name CodeDeployDefault.OneAtATime \
  --ec2-tag-filters Key=Name,Value=cms.tomcat,Type=KEY_AND_VALUE \
  --service-role-arn arn:aws:iam::15xxxxxx698:role/CodeDeployServiceRole

最後一行爲上面創建的ServiceRole(讓吧返回值記錄下來來着,現在用到了)
然後創建一個部署,首次部署,跟代碼更新部署,和回滾部署,本質是一樣,沒區別

aws deploy create-deployment \
  --application-name CMSTomcatApplication \
  --deployment-config-name CodeDeployDefault.OneAtATime \
  --deployment-group-name CMSTomcatApplication \
  --s3-location bucket=CYPayCodeDeployBucket,bundleType=zip,key=cms.front.v1.0.zip

返回值

{
    "deploymentId": "d-ROL5D7YPZ"
}

可以查看該部署的狀態

aws deploy get-deployment --deployment-id d-ROL5D7YPZ --query 'deploymentInfo.status'
"InProgress" 

等進度從InProgress變成Succeeded就成功了,然後瀏覽器訪問下自己的代碼是否OK

三、 做次代碼更新和回滾
本質是一樣的,只不過版本包不同而已,可以吧首次部署的一些無用腳本刪除,回滾的話,會刪除就得部署新的
命令行的話,還是這樣

aws deploy create-deployment \
  --application-name CMSTomcatApplication \
  --deployment-config-name CodeDeployDefault.OneAtATime \
  --deployment-group-name CMSTomcatApplication \
  --s3-location bucket=CYPayCodeDeployBucket,bundleType=zip,key=cms.front.v1.1.zip

區別在於使用的版本包版本不同
版本更新和回退,使用web console用瀏覽器來做最爽
選擇你的Application,進到DeploymentGroup裏,然後選擇Deploy New Revision
此時Application和DeploymentGroup的下拉菜單應該已經都默認選好了,還可以改
選擇Revision Type,可選爲S3或者github,此例爲S3 bucket
Revision Location裏寫上版本包的全路徑,s3://CYPayCodeDeployBucket/cms.front.v1.1.zip
File Type會自動識別,支持zip,tar,tar.gz,別的格式沒試過,war跟zip一樣的吧
Deployment Description寫上版本說明
Deployment Config有三種可選
CodeDeployDefault.AllAtOnce, CodeDeployDefault.HalfAtATime, CodeDeployDefault.AllAtATime.
AllAtOnce:組中所有實例一次部署完(同時併發?),有成功的實例就算此次部署成功,都部署失敗就算此次部署失敗
HalfAtATime:一次部署一半實例,分兩次部署完,一半以上實例成功纔算部署成功,一半以上失敗就算部署失敗
AllAtATime:一次部署一臺,直至全部完成,所有實例都部署成功纔算成功,有失敗的就算部署失敗(這個最符合我的需求,可以在起服腳本中加上sleep來實現一臺一臺來更新,並間隔幾百秒)
點擊Deploy Now來完成部署,等到刷新狀態爲Succeeded就成功了,接下來就是測試

總結:
創建好Application和DeploymentGroup之後,跟配置管理工程師協定好往版本中添加的文件,然後按時間+項目+版本號的方式打包,並上傳到S3上,然後代碼的更新回退,由測試和開發同學在瀏覽器上就能完成,省的自己寫代碼更新平臺了
上新項目的時候,也可以直接利用這個服務來實現,首次部署腳本是得寫的複雜點,裝上依賴軟件和設置環境
用好之後,甚至能不用碰ssh工具就能在瀏覽器或者用代碼把活幹完

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章