1. 程式人生 > >AWS CodePipeline部署Maven專案至EC2

AWS CodePipeline部署Maven專案至EC2

# 背景 > 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