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 官方文件

我們安裝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許可權管理服務中檢視:

在IAM中,選擇使用者選項,然後開啟一個使用者,來到安全證照選項下面:

上圖箭頭所標識的就是登陸Code Commit的方式,SSH和賬號密碼選擇一種進行登陸即可。

AWS CodeArtifact

AWS CodeArtifact 是一種完全託管的構件儲存庫服務,它使各種規模的組織都可以輕鬆安全地儲存、釋出及共享其軟體開發過程中所使用的軟體包。

我們們的專案使用的是自己寫的微服務框架,原本是儲存在公司的Nexus製品倉庫中(Maven私服),為了方便AWS CodeBuild打包,所以我們將專案所需要的jar包都上傳到這個服務中。

因為我們使用的是Maven來進行Deploy,按照官方的指南,需要通過以下的配置來通過驗證:

前提:安裝好AWS CLI,並且配置好自己的賬號。

首先修改maven的setting檔案:

<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
    <localRepository>你的本地Maven倉庫地址</localRepository>
	<pluginGroups></pluginGroups>
    <proxies></proxies>
	<servers>
		<server>
            <id>codeartifact</id>
            <username>aws</username>
            <password>${env.CODEARTIFACT_TOKEN}</password>
        </server>
	</servers>
    <profiles>
        <profile>
            <id>default</id>
            <repositories>
                <repository>
                    <id>codeartifact</id>
                    <url>你的CodeArtifact訪問地址</url>
                </repository>
            </repositories>
        </profile>
        <profile>
            <id>jdk-1.8</id>
            <activation>
                <activeByDefault>true</activeByDefault>
                <jdk>1.8</jdk>
            </activation>
            <properties>
                <maven.compiler.source>1.8</maven.compiler.source>
                <maven.compiler.target>1.8</maven.compiler.target>
                <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
            </properties>
        </profile>
    </profiles>
    <activeProfiles>
        <activeProfile>default</activeProfile>
    </activeProfiles>
</settings>

可以從上面的配置檔案中看到,我們是從環境變數中獲取密碼的,因為其密碼只能通過AWS CLI生成臨時的憑證,而且生成的Token只能保持12小時有效。

生成密碼的方式:

macOS or Linux:

$ export CODEARTIFACT_TOKEN=`aws codeartifact get-authorization-token --domain mydomain --domain-owner domain-owner-id --query authorizationToken --output text`

Windows 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產品,點選下一步

在附加許可權中,搜尋CodeArtifact,選擇其一,我這裡選擇的是AdminAccess,下面一個是隻讀

只有選擇了這兩個的其中一個,我們才能通過CodeBuild訪問CodeArtifact

然後跳過標籤,下一步,建立一個名字,自擬。點選建立角色即可。

建立CodeBuild構建專案

來到AWS CodeBuild頁面,建立構建專案:

這裡只說明幾個需要注意的選項

源我們使用CodeCommit

可以選擇源是來源於CodeCommit的哪一個分支或者Git標籤或者提交的ID。

打包環境選擇標準的Standard環境即可,角色選擇現有服務角色,使用我們剛才建立的哪個角色即可。

需要注意的是這裡,BuildSpec.yml檔案,這個檔案是具體的打包步驟,如果要配合CodeDeploy部署程式,還需要一個appspec.yml檔案 Build+Deploy官方示例

這是我們專案中的其中一個服務,我們專案啟動只需要api模組中的jar包

這裡的settings-aws.xml為在CodeBuild中進行maven打包的setting配置檔案。

buildspec.yml

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

我這裡將其取名為:ChuanXiaoCodeDeployInstanceRole

如果你的伺服器沒有角色,需要去將你的伺服器角色改為建立的新角色

配置CodeDeploy角色

我們還要在這裡建立一個 CodeDeploy 的應用使用的角色。再次點選「建立角色」。選擇角色為「Amazon EC2」,在附加策略時依然搜尋 CodeDeploy,但是這次選擇的策略叫做:AWSCodeDeployRole

我這裡將其取名為CodeDeployServiceRole

安裝Deploy元件

如果需要使用Deploy部署你的服務,則需要安裝Deploy元件: 安裝CodeDeploy官方文件

登入你的伺服器,執行以下命令

$ 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選項中的應用程式,點選建立應用程式

輸入應用程式的名字,選擇應用程式需要部署到的平臺,點選建立應用程式

建立部署組

應用程式建立完畢之後,點進去,然後點選建立部署組

這裡的角色選擇我們剛才建立的角色

這裡選擇就地部署,因為我使用的是EC2,所以選擇AmazonEC2例項,通過標籤來標識選擇哪一個Ec2例項,我這裡的EC2例項的name就為ChuangXiaoEc2,所以這裡通過name設定。

這是我們ES2的資訊:

最後的負載均衡這裡,因為沒有這個需求,就沒有選擇

編寫appspec.yml檔案

在配置CodeBuild的時候說道,我們需要appspec.yml檔案,這個檔案是做什麼的呢?

appspec.yml是YAML格式、用於定於CodeDeploy服務在整個階段所做的操作和檔案拷貝路徑和許可權等。

也就是說定義CodeDeploy在部署的機器上面拷貝哪些檔案,定義和描述被拷貝到目標伺服器上的檔案拷貝後的許可權,定義各個階段執行的操作。具體的解析可以參考這篇文章:appspec.yml檔案解析

appspec.yml示例

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-archivecopy到設定的destination路徑中

hooks區段就是定義各個階段執行的操作,這裡的BeforeInstall為:檔案複製到目標目錄之前的操作

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表示檔案複製完之後的操作

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頁面,點選建立流水線

第一步設定流水線名字和角色,這裡自擬名字,選擇一個新服務角色就好。

這裡源選擇AWS CodeCommit,設定好分支,這樣當這個分支發生變化的時候,就會觸發整個流水線。

構建選擇AWS CodeBuild,選擇我們之前在CodeBuild中建立的構建專案

部署選擇AWS CodeDeploy,選擇我們建立的應用程式和部署組。

最後點選建立流水線,這樣一個流水線就建立完畢了。

結果

當設定的CodeCommit分支發生變動的時候,就觸發CodeBuild,然後CodeBuild打包成功之後,將buildspec.yml檔案中設定的需要傳輸的檔案告訴CodeDeploy,然後CodeDeploy將檔案上傳至伺服器。最後CodeDeploy執行執行指令碼,執行專案。

相關文章