AWS CodePipeline部署Maven專案至EC2
阿新 • • 發佈:2020-11-25
# 背景
> AWS CodePipeline 是一種持續性的整合與交付服務,可以實現快速而可靠的應用程式和基礎設施更新。根據您定義的釋出流程模型,只要程式碼發生變更,CodePipeline 便會生成、測試和部署您的程式碼。
情況是這樣的,最近公司在搞APN認證,需要將專案遷移到AWS上面,並且搭建一套CI/CD流程。因為專案是SpringCloud微服務,所以需要部署多個服務。
經過調研,我們做了以下設計:
我們設計,將程式碼推送到**AWS Code Commit**,將專案需要用到的自研jar包上傳到**AWS Code Artifact**。程式碼推送到**AWS Code Commit**時,**AWS Code Pipeline**觸發打包服務,使用**AWS Code Build**打包的時候,訪問**AWS Code Artifact**去拿jar包。打完jar包之後,**AWS Code Pipeline**觸發**AWS Code Deploy**上傳jar包至**EC2**(ECS也可以,看需求),然後**AWS Code Deploy**呼叫配置好的指令碼,備份和啟動專案。
所以除了專案中用到的資料庫,中介軟體之外不談,我們需要的服務有:
- 程式碼倉庫:使用AWS Code Commit
- 製品倉庫: 使用AWS Code Artifact
- 專案打包服務: 使用 AWS Code Build
- 部署服務: AWS Code Deploy
- 流水線服務: AWS Code Pipeline
- 虛擬機器EC2
AWS Code Pipeline 負責將這些服務串聯起來,形成工作流。
產品都使用的孟買地區的服務(ap-south-1)
# 安裝AWS CLI
因為需要使用AWS服務,所以首先我們得安裝AWS CLI命令列工具,並且配置好自己的賬號資訊,下載和配置AWS CLI參考:[AWS CLI 官方文件](https://docs.aws.amazon.com/zh_cn/cli/latest/userguide/cli-chap-welcome.html)
我們安裝AWS CLI主要是用來通過Code Artifact的認證,Code Artifact必須使用AWS CLI來生成臨時憑證訪問。
# AWS Code Commit
> AWS CodeCommit 是一種完全託管型原始碼控制服務,使公司可以輕鬆地託管安全和高度可擴充套件的專用 Git 儲存庫。CodeCommit 使您無需運作自己的源控制系統或擔心基礎設施的擴充套件能力。
這一步其實可以不做,因為AWS Code Build可以從github中拉取程式碼,但是為了認證APN,最好都使用AWS的服務,所以加了這一步。
在AWS Code Commit中,直接建立儲存庫即可,最主要的是怎麼連線。
Code Commit可以使用賬號密碼訪問,就像github一樣。賬號密碼需要在IAM許可權管理服務中檢視:
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125142043904-1616716148.png)
在IAM中,選擇使用者選項,然後開啟一個使用者,來到安全證書選項下面:
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125142108941-920411146.png)
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125142118845-1624659559.png)
上圖箭頭所標識的就是登陸Code Commit的方式,SSH和賬號密碼選擇一種進行登陸即可。
# AWS CodeArtifact
> AWS CodeArtifact 是一種完全託管的構件儲存庫服務,它使各種規模的組織都可以輕鬆安全地儲存、釋出及共享其軟體開發過程中所使用的軟體包。
咱們的專案使用的是自己寫的微服務框架,原本是儲存在公司的Nexus製品倉庫中(Maven私服),為了方便AWS CodeBuild打包,所以我們將專案所需要的jar包都上傳到這個服務中。
因為我們使用的是Maven來進行Deploy,按照官方的指南,需要通過以下的配置來通過驗證:
前提:安裝好AWS CLI,並且配置好自己的賬號。
首先修改maven的setting檔案:
```xml
你的本地Maven倉庫地址
codeartifact
aws
${env.CODEARTIFACT_TOKEN}
default
codeartifact
你的CodeArtifact訪問地址
jdk-1.8
true
1.8
1.8
1.8
1.8
default
```
可以從上面的配置檔案中看到,我們是從環境變數中獲取密碼的,因為其密碼只能通過AWS CLI生成臨時的憑證,而且生成的Token只能保持12小時有效。
生成密碼的方式:
macOS or Linux:
```shell
$ export CODEARTIFACT_TOKEN=`aws codeartifact get-authorization-token --domain mydomain --domain-owner domain-owner-id --query authorizationToken --output text`
```
Windows PowerShell:
```powershell
> $CODEARTIFACT_TOKEN = aws codeartifact get-authorization-token --domain my-domain --domain-owner domain-owner-id --query authorizationToken --output text
```
你需要將介面中的 export 配置的
–my-domain
–domain-owner-id
2 個引數替換成你配置的引數。
通過上面的命令就會生成 Token, 然後將這個 token 儲存到系統變數中。
如果一切順利,你將會看到你的螢幕中輸出上面的字串,上面的字串就是你 Maven 登入使用的 token。
登入之後,我們將專案所需要的Jar包上傳至AWS CodeArtifact
# AWS CodeBuild
> AWS CodeBuild 是一項完全託管的持續整合服務,可編譯原始碼、執行測試以及生成可供部署的軟體包。使用 CodeBuild,您無需配置、管理和擴充套件自己的生成伺服器。CodeBuild 可以持續擴充套件並同時處理多項生成任務,因此您的構建任務不會在佇列中等待。
我們使用AWS CodeBuild對專案進行打包
## 建立CodeBuild角色
在使用AWS CodeBuild之前,我們需要建立其角色:
來到IAM頁面,點選建立角色,選擇`CodeBuild`產品,點選下一步
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125142154290-2025871220.png)
在附加許可權中,搜尋CodeArtifact,選擇其一,我這裡選擇的是AdminAccess,下面一個是隻讀
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125142245147-1811346282.png)
只有選擇了這兩個的其中一個,我們才能通過CodeBuild訪問CodeArtifact
然後跳過標籤,下一步,建立一個名字,自擬。點選建立角色即可。
## 建立CodeBuild構建專案
來到AWS CodeBuild頁面,建立構建專案:
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125142317819-808246229.png)
這裡只說明幾個需要注意的選項
源我們使用CodeCommit
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125142347770-2062107366.png)
可以選擇源是來源於CodeCommit的哪一個分支或者Git標籤或者提交的ID。
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125142408522-598064432.png)
打包環境選擇標準的Standard環境即可,角色選擇現有服務角色,使用我們剛才建立的哪個角色即可。
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125142435526-195878656.png)
需要注意的是這裡,BuildSpec.yml檔案,這個檔案是具體的打包步驟,如果要配合CodeDeploy部署程式,還需要一個appspec.yml檔案 [Build+Deploy官方示例](https://docs.aws.amazon.com/zh_cn/codebuild/latest/userguide/sample-codedeploy.html)
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125142456179-1373623536.png)
這是我們專案中的其中一個服務,我們專案啟動只需要api模組中的jar包
這裡的settings-aws.xml為在CodeBuild中進行maven打包的setting配置檔案。
buildspec.yml
```yaml
version: 0.2
phases:
install:
runtime-versions:
java: corretto8
pre_build:
commands:
- pip3 install awscli --upgrade --user
- export CODEARTIFACT_TOKEN=`aws codeartifact get-authorization-token --domain xxx --domain-owner xxx --query authorizationToken --output text`
build:
commands:
- echo Build started on `date`
post_build:
commands:
- echo Build completed on `date`
- mvn package -Dmaven.test.skip=true --settings ./settings-aws.xml
- rm -rf vehicles-service-api/target/*jar.original
- rm -rf vehicles-service-api/target/*-javadoc.jar
- rm -rf vehicles-service-api/target/*-sources.jar
artifacts:
files:
- vehicles-service-api/target/*.jar
- appspec.yml
- backup.sh
- start.sh
discard-paths: yes
```
注意:
- `pre_build.commands`中執行的是CodeArtfact驗證的過程,如果CodeBuild的角色沒有CodeArtfactAccess的許可權,這一步則會驗證失敗。
- `artifacts.files`是我們打完包之後,會將這裡定義的檔案交給CodeDeploy
appspec.yml、backup.sh和start.sh涉及CodeDeploy服務,在下一節介紹。
# AWS CodeDeploy
> AWS CodeDeploy 是一項完全託管的部署服務,可自動將軟體部署到計算服務,例如 Amazon EC2、AWS Lambda 以及您的本地伺服器。藉助 AWS CodeDeploy,您可以更輕鬆地快速釋出新功能、避免在應用程式部署過程中出現停機,並簡化應用程式的更新工作。
CodeDeploy的配置思路:
1. 配置角色
2. 安裝Deploy元件
3. 建立應用程式
4. 在應用程式中建立部署組,設定部署在哪裡
5. 編寫appspec.yml檔案
## 配置角色
### 配置伺服器角色
無論使用的是ECR還是EC2,我們都需要給伺服器配置許可權,這裡我使用的是EC2
來到IAM角色頁面,如果你沒有EC2的角色,則建立一個新角色,選擇角色型別為Amazon EC2。如果你有EC2的角色,則點選附加角色
在附加策略裡面搜尋 CodeDeploy;然後選擇`AmazonEC2RoleforAWSCodeDeploy`
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125142535627-1813497602.png)
我這裡將其取名為:ChuanXiaoCodeDeployInstanceRole
如果你的伺服器沒有角色,需要去將你的伺服器角色改為建立的新角色
### 配置CodeDeploy角色
我們還要在這裡建立一個 CodeDeploy 的應用使用的角色。再次點選「建立角色」。選擇角色為「Amazon EC2」,在附加策略時依然搜尋 CodeDeploy,但是這次選擇的策略叫做:`AWSCodeDeployRole`
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125142605871-663639656.png)
我這裡將其取名為CodeDeployServiceRole
## 安裝Deploy元件
如果需要使用Deploy部署你的服務,則需要安裝Deploy元件: [安裝CodeDeploy官方文件](https://docs.aws.amazon.com/zh_cn/codedeploy/latest/userguide/codedeploy-agent-operations-install-linux.html)
登入你的伺服器,執行以下命令
```shell
$ sudo yum update
$ sudo yum install ruby
$ sudo yum install wget
$ cd /home/ec2-user
# 將以下命令的bucket-name換為您CodeDeploy所在區域的S3桶名字,比如:美國東部(俄亥俄)區域,請將儲存桶名稱替換為 aws-codedeploy-us-east-2
# 將以下命令的region-identifier換為您CodeDeploy所在區域的表示符,比如美國東部(俄亥俄)區域,請將區域識別符號替換為 us-east-2
$ wget https://bucket-name.s3.region-identifier.amazonaws.com/latest/install
$ chmod +x ./install
$ sudo ./install auto
# 檢查服務是否正在執行
$ sudo service codedeploy-agent status
# 開啟服務
$ sudo service codedeploy-agent start
```
## 建立應用程式
點選CodeDeploy選項中的應用程式,點選建立應用程式
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125142632653-813154235.png)
輸入應用程式的名字,選擇應用程式需要部署到的平臺,點選建立應用程式
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125142706245-62775759.png)
## 建立部署組
應用程式建立完畢之後,點進去,然後點選建立部署組
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125142740937-1215816273.png)
這裡的角色選擇我們剛才建立的角色
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125142803461-1923705691.png)
這裡選擇就地部署,因為我使用的是EC2,所以選擇AmazonEC2例項,通過標籤來標識選擇哪一個Ec2例項,我這裡的EC2例項的name就為ChuangXiaoEc2,所以這裡通過name設定。
這是我們ES2的資訊:
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125142853280-2039943636.png)
最後的負載均衡這裡,因為沒有這個需求,就沒有選擇
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125142905881-777569123.png)
## 編寫appspec.yml檔案
在配置CodeBuild的時候說道,我們需要appspec.yml檔案,這個檔案是做什麼的呢?
appspec.yml是YAML格式、用於定於CodeDeploy服務在整個階段所做的操作和檔案拷貝路徑和許可權等。
也就是說定義CodeDeploy在部署的機器上面拷貝哪些檔案,定義和描述被拷貝到目標伺服器上的檔案拷貝後的許可權,定義各個階段執行的操作。具體的解析可以參考這篇文章:[appspec.yml檔案解析](https://blog.csdn.net/fedora18/article/details/44237647)
appspec.yml示例
```yaml
version: 0.0
os: linux
files:
- source: /
destination: /home/ec2-user/chengdu_iot/vehicles-service/standby_dir
hooks:
BeforeInstall:
- location: backup.sh
timeout: 3000
ApplicationStart:
- location: start.sh
timeout: 3000
```
這個檔案的`version`只能填0.0,我們伺服器是linux,所以`os`為linux
**files**:定於檔案對映關係
`source`檔案路徑是是相對於本此部署包的相對路徑,如果是`/`,表示本此部署包裡的全部檔案和目錄
需要注意的是,本此部署包中的檔案,就是你在Buildspec.yml中定義的artifacts.files的檔案,CodeDeploy會通過Buildspec.yml,獲取需要哪些檔案,然後上傳至伺服器。linux系統下,版本包會被上傳到`/opt/codedeploy-agent/deployment-root/deployment-group-id/deployment-id/deployment-archive`,windows系統會被上傳到`C:\ProgramData\Amazon\CodeDeploy\deployment-group-id\deployment-id\deployment-archive`
`destination`這裡是被部署伺服器的完整路徑(絕對路徑),會將`source`中設定的檔案,從`/opt/codedeploy-agent/deployment-root/deployment-group-id/deployment-id/deployment-archive`中**copy**到設定的`destination`路徑中
**hooks**區段就是定義各個階段執行的操作,這裡的`BeforeInstall`為:檔案複製到目標目錄之前的操作
```shell
project_dir=/home/ec2-user/chengdu_iot/vehicles-service
standby_dir=$project_dir/standby_dir
backup_dir=$project_dir/backup
cd $project_dir
if [ ! -d $standby_dir ]; then
echo "建立等待資料夾"
mkdir -p $standby_dir
else
echo "等待資料夾已存在"
fi
if [ ! -d $backup_dir ]; then
echo "建立備份資料夾"
mkdir -p $backup_dir
else
echo "備份資料夾已存在"
fi
jar_name=`ls | grep jar$ | awk '{print $1}'`
if [ -n "$jar_name" ];then
mv ./$jar_name ./backup/$jar_name.`date +%Y%m%d%H%M%S`
fi
```
這個指令碼判斷專案資料夾是否存在,不存在則建立。再判斷jar包是否存在,存在則進行備份。
`ApplicationStart`表示檔案複製完之後的操作
```shell
port=9083
project_dir=/home/ec2-user/chengdu_iot/vehicles-service
standby_dir=$project_dir/standby_dir
cd $standby_dir
jar_name=`ls | grep jar$ | awk '{print $1}'`
mv $jar_name ../
cd ..
rm -rf standby_dir
pid=`netstat -anp|grep $port|awk '{printf $7}'|cut -d/ -f1`
if [ -n "$pid" ]
then
if [ "$pid" != "-" ]
then
echo "kill -9 的pid:" $pid
kill -9 $pid
fi
fi
nohup java -Xms1g -Xmx1g -jar $jar_name --spring.profiles.active=test --server.port=$port >console.log 2>&1 &
```
這個指令碼做了三件事,將jar包從等待資料夾中拿出來,然後刪掉等待資料夾。然後判斷是否有這個jar包的程序在執行,如果有就殺掉。最後執行jar包
# AWS CodePipeline
> AWS CodePipeline 是一種持續性的整合與交付服務,可以實現快速而可靠的應用程式和基礎設施更新。根據您定義的釋出流程模型,只要程式碼發生變更,CodePipeline 便會生成、測試和部署您的程式碼。
對於AWS Pipeline我的理解是,將以上服務串聯起來,當設定的CodeCommit分支發生變動的時候,就觸發CodeBuild,然後CodeBuild打包成功之後,將buildspec.yml檔案中設定的需要傳輸的檔案告訴CodeDeploy,然後CodeDeploy將檔案上傳至伺服器。最後CodeDeploy執行執行指令碼,執行專案。
在CodePipeline頁面,點選建立流水線
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125142944399-1389232840.png)
第一步設定流水線名字和角色,這裡自擬名字,選擇一個新服務角色就好。
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125143002213-1104737122.png)
這裡源選擇AWS CodeCommit,設定好分支,這樣當這個分支發生變化的時候,就會觸發整個流水線。
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125143023212-197917831.png)
構建選擇AWS CodeBuild,選擇我們之前在CodeBuild中建立的構建專案
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125143037115-195555174.png)
部署選擇AWS CodeDeploy,選擇我們建立的應用程式和部署組。
最後點選建立流水線,這樣一個流水線就建立完畢了。
# 結果
當設定的CodeCommit分支發生變動的時候,就觸發CodeBuild,然後CodeBuild打包成功之後,將buildspec.yml檔案中設定的需要傳輸的檔案告訴CodeDeploy,然後CodeDeploy將檔案上傳至伺服器。最後CodeDeploy執行執行指令碼,執行專案。
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125143048567-449693006.png)
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125143053425-491594549.png)
![](https://img2020.cnblogs.com/blog/2176443/202011/2176443-20201125143103922-2866231