AWS codebuild + jenkins + github 实践CI/CD

news/2024/11/25 6:21:39/

前文

本文使用 Jenkins 结合 CodeBuild, CodeDeploy 实现 Serverless 的 CI/CD 工作流,用于自动化发布已经部署 lambda 函数。 在 AWS 海外区,CI/CD 工作流可以用 codepipeline 这项产品来方便的实现,

CICD 基本概念

  • 持续集成( Continuous Integration,简称CI ) 是指在应用代码的新组件集成到共享存储库之后自动测试和构建软件的流程。这样一来,就可以打造出始终处于工作状态的应用“版本”。
  • 持续交付( Continuous Deployment, 简称CD )是指将CI流程中创建的应用交付到类似生产环境的过程,在该过程中将对应用进行额外的自动化测试,以确保应用在部署到生产环境以及交付到真实用户手中时能够发挥预期作用。

架构综述

本文最终达到的效果为,源代码在 Github repo 中,每当有新的 commit,将自动触发 Jenkins CICD 工作流,Jenkin 会利用 CodeBuild 做构建,以及CodeDeploy 自动部署发布 lambda 新版本。

jenkins环境准备

jenkins EC2安装

先拉一个每月750小时免费的 EC2 实例t2.micro,  最后配置一个固定的弹性ip,后面如果时不时要用停止/启动EC2 实后ip不用再重复配置

登录EC2 安装jenkins,  我使用的是jenkins.war的方式部署为了避免jenkins 的使用环境上一些坑

jenkins.war的下载地址jenkins.war

安装jdk-17

更新OS
sudo yum update -y设置yum源
sudo wget -O /etc/yum.repos.d/jenkins.repo \https://pkg.jenkins.io/redhat-stable/jenkins.repo导入公钥
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io-2023.key升级包
sudo yum upgrade安装java
sudo dnf install java-17-amazon-corretto -y

jenkins.war放到/usr/local/jenkins 目录下,编辑 /etc/init.d/jenkins 作为启动脚本

#!/bin/bash# 在执行过程中若遇到使用了未定义的变量或命令返回值为非零,将直接报错退出
set -eu
# Default-Start: 2 3 4 5# 检查参数个数
if [ "${#}" -lt 1 ]; thenecho " 脚本使用示例: service jenkins start|stop|restart "exit
fi# 获取脚本第一个参数
APP_OPT=${1}
# 端口
APP_PORT=9001
# 名称
APP_NAME=jenkins
# jar名 | war名
APP_JAR=${APP_NAME}.war
# 程序根目录
APP_JAR_HOME=/usr/local/jenkins
# 日志名
APP_LOG_NAME=app-jenkins
# 日志根目录
APP_LOG_HOME=/usr/local/jenkins/log
# 程序运行参数
JAVA_OPTS="--httpPort=${APP_PORT}"echo "本次操作服务名:[${APP_NAME}]"
echo "本次操作选择:[${APP_OPT}]"# 停止
function stop(){echo "<-------------------------------------->"echo "[${APP_NAME}] ... stop ..."# 查看该jar进程pid=`ps -ef | grep ${APP_NAME} | grep -v 'grep' | awk '{print $2}'`echo "[${APP_NAME}] pid="${pid}# 存在则kill,不存在打印一下吧if [ "${pid}" ]; thenkill -9 ${pid}# 检查kill是否成功if [ "$?" -eq 0 ]; thenecho "[${APP_NAME}] stop success"elseecho "[${APP_NAME}] stop fail"fielseecho "[${APP_NAME}] 进程不存在"fi
}# 运行
function start(){echo "<-------------------------------------->"echo "[${APP_NAME}] ... start ..."cd ${APP_JAR_HOME}echo "当前路径:`pwd`"# 赋予可读可写可执行权限chmod 777 ${APP_JAR}echo "启动命令: nohup java -jar ${APP_JAR} ${JAVA_OPTS} >> ${APP_LOG_HOME}/${APP_LOG_NAME}.log 2>&1 &"sudo nohup java -jar ${APP_JAR} ${JAVA_OPTS} >> ${APP_LOG_HOME}/${APP_LOG_NAME}.log 2>&1 &if [ "$?" -eq 0 ]; thenecho "[${APP_NAME}] start success"elseecho "[${APP_NAME}] start fail"fi
}# 重启
function restart(){echo "<-------------------------------------->"echo "[${APP_NAME}] ... restart ..."stopsleep 3start
}# 多分支条件判断执行参数
case "${APP_OPT}" in"stop")stop;;"start")start;;"restart")restart;;*)echo " 提示:不支持参数 命令 -> ${APP_OPT}";;
esac

jenkins工作目录磁盘空间挂载

因为我们使用的micro的EC2,  需要给jenkins 工作目录挂载更大的空间

Jenkins 默认是安装在/root/.jenkins 目录下,查看目录下使用和剩余空间

df -h /root/.jenkins/

将 /dev/nvme0n1p1 作为你的设备进行挂载并增加 /root/.jenkins 的空间,以下是相应的步骤: 步骤 1: 创建挂载点创建一个新的目录作为挂载点(例如 /mnt/jenkins_data):

sudo mkdir -p /mnt/jenkins_data

步骤 2: 挂载文件系统 将设备 /dev/nvme0n1p1 挂载到新创建的目录:

sudo mount /dev/nvme0n1p1 /mnt/jenkins_data

步骤 3: 更新 /etc/fstab 为了确保在重启后仍然保持挂载,需要更新 /etc/fstab 文件。打开该文件进行编辑:

sudo nano /etc/fstab

在文件末尾添加以下行:

/dev/nvme0n1p1 /mnt/jenkins_data ext4 defaults,nofail 0 2

确保根据实际文件系统类型(如 ext4)进行调整。 步骤 4: 移动 Jenkins 数据 如果 /root/.jenkins 中的数据需要迁移到新的挂载点:


sudo cp -r /root/.jenkins/* /mnt/jenkins_data/ sudo ln -s /mnt/jenkins_data /root/.jenkins

查看现在的工作空间大小

micro 免费的同时就得随时手动挂载确保空间足够,后面jenkins 交换空间不够也是这样解决的,

Dashboard -> 系统管理 -> 节点列表上, 如果资源不够是无法启动构建job的

启动jenkins

查看 Jenkins 初始密码

sudo cat /var/lib/jenkins/secrets/initialAdminPassword

登录后安装必要的插件会花费一些时间

Github 准备

 创建一个项目类似于我做实践用的

https://github.com/chenrui2200/aws-jenkins-codepipeline

 develop setting 里生成token


 

保存该token后面会用到多次

配置webhooks

在项目内setting里配置webhooks ,  PayloadUrl 填写 <jenkins_url>/github-webhook/

点击保存

jenkins system configure 配置access token

把access token 录入到credentials

跳转system configuration

找到github server,  使用access token配置https://api.github.com

添加认证方式,在箭头处填写github access token

点击测试连接出现下面字样说明配置成功

项目文件准备

新建基于 python 的 lambda 函数。此 lambda 函数为我们的目标 lambda 函数,在本实验完成后,每当有新的 commit,都会触发此 lambda 函数进行自动化部署。 如您不清楚步骤,请参考创建您的第一个 Lambda 函数 此文重在搭建 CICD 流水线,代码会直接用默认生成的 python 代码 lambda_function.py。

publish 此 lambda,版本为1,并且创建别名(alias)。

除此以外,还需要添加另外两个文件

  • appspec.template.yaml, 用于 codedeploy 配置文件。请将此文件当中的函数名以及 alias(别名)替换为自己对应的值。
  • buildspec.yml,用于 codebuild 配置文件,修改替换文件中尖括号标注部分(去掉尖括号)。

buildspec.yml

version: 0.2phases:install:runtime-versions:python: 3.7commands:- echo pre Installing ...pre_build:commands:- echo prebuild,Installing update ...# 基本环境更新#- yum update -ybuild:commands:- echo Build started on `date`post_build:commands:- ls - mkdir build- # 替换所有尖括号标注,替换时,去掉尖括号- CurrentVersion=$(echo $(aws lambda get-alias --function-name <替换为自己的 lambda 函数 ARN> --name <替换为自己的lambda alias> --region <your_region> | grep FunctionVersion | tail -1 |tr -cd "[0-9]"))- zip -r ./build/lambda.zip ./lambda_function.py- aws lambda update-function-code --function-name <替换为自己的 lambda 函数 ARN> --zip-file fileb://build/lambda.zip  --region <your_region> --publish- TargetVersion=$(echo $(aws lambda list-versions-by-function --function-name <替换为自己的 lambda 函数 ARN> --region <your_region> | grep Version | tail -1 | tr -cd "[0-9]"))- echo $CurrentVersion- echo $TargetVersion- sed -e 's/{{CurrentVersion}}/'$CurrentVersion'/g' -e 's/{{TargetVersion}}/'$TargetVersion'/g' appspec.template.yaml > appspec.yaml- aws s3 cp appspec.yaml s3://<替换为自己的S3 Bucket名称>/jenkins/codedeploy/appspec.yaml- # 替换 first-try-with-jenkins 为自己的codedeploy名称- aws deploy create-deployment --application-name first-try-with-jenkins --deployment-group-name first-try-with-jenkins --s3-location bucket='<替换为自己的S3 Bucket名称>',key='jenkins/codedeploy/appspec.yaml',bundleType=YAML
artifacts:type: yamlfiles:- appspec.yaml

appspec.template.yaml

version: 0.0
Resources:- test: # Replace "MyFunction" with the name of your Lambda functionType: AWS::Lambda::FunctionProperties:Name: "test" # Specify the name of your Lambda functionAlias: "beta" # Specify the alias for your Lambda functionCurrentVersion: "{{CurrentVersion}}" # Specify the current version of your Lambda functionTargetVersion: "{{TargetVersion}}" # Specify the version of your Lambda function to deploy

lambda_function.py

import jsondef lambda_handler(event, context):# TODO implementreturn {'statusCode': 200,'body': json.dumps('Hello from Lambda!')}

AWS 准备

Codebuild 准备

新建codebuild项目

【源】选择github, 点击管理认证凭证配置访问凭证

认证成功

其他选项不用动

选择EC2 相同的vpc

使用buildspec文件构建,文件名对应的是github项目里的buildspec.yml 文件名称

codebuild选择的role需要具备 s3 codebuild的权限

CodeDeploy 准备

计算平台选择lamda

创建部署组组

codedeploy选择的role需要具备 codedeploy 的权限

构建CI/CD 流程

创建一个 Jenkin 的项目,配置 codedeploy 相应信息

新建项目之前,先安装 codebuild 的插件。点击 系统管理 -- 插件管理(plugin)

新建一Jenkins个项目,点击“Create a new project” -- "freestyle project"

配置Github项目的地址,源代码管理选择Git方式。

上面credentials没有显示secret text类别的,需要安装Plain Credentials Plugin。您还需要安装Credentials Binding Plugin来传递凭据, 同时宿主机上需要安装 git

触发构建,选择 Github hook trigger for GITScm polling

配置 AK, SK , region, project-name

尝试提交push下代码, 看到push事件已经触发了jenkins

jenkins端插件已经触发了codebuild 去构建,提交者是codebuild-jenkins plugin

整个流程已经打通, 查看jenkins 的构建日志

Codebuild 日志也看到成功了

查看lambda 函数已经成功更新了


http://www.ppmy.cn/news/1549746.html

相关文章

CTF之密码学(键盘加密)

在CTF&#xff08;Capture The Flag&#xff0c;夺旗赛&#xff09;中&#xff0c;键盘加密是一种独特而有趣的加密方式&#xff0c;它巧妙地利用了键盘的布局和坐标进行信息的加密和解密。以下是关于CTF中键盘加密的详细解释&#xff1a; 一、键盘加密的定义 键盘加密是通过…

【网络安全设备系列】4、漏洞扫描设备

0x00 定义&#xff1a; 漏洞扫描是指基于漏洞数据库&#xff0c;通过扫描等手段对指定的远程或者本地计算机系统的安全脆弱性进行检测&#xff0c;发现可利用的漏洞的一种安全检测&#xff08;渗透攻击&#xff09;行为。 0x01 主要功能&#xff1a; 可以对网站、系统、数据…

Unity图形学之法线贴图原理

1.正常贴图&#xff1a;RGBA 4通道 每个通道取值范围 0-255 贴图里面取值是 0-1 2.法线贴图&#xff1a;法线怎么存入正常贴图的过程 每个通道里面存储的是一个向量(x,y,z,w) 通常我们会对应xyzw为rgba 存储值的范围也是0-1向量的取值范围是 -1到1法线怎么存入正常贴图的过程&…

TCP/IP--黑客想要通过TCP攻击,会如何攻击,应该怎么应对。

黑客想要通过TCP攻击&#xff0c;会如何攻击&#xff0c;应该怎么应对。 SYN Flood 攻击时DDOS攻击一种&#xff0c;洪水泛滥。黑客发送大量的SYN请求到目标服务器&#xff0c;但是不完成三次握手和四次挥手的过程&#xff0c;不发送ACK响应&#xff0c;服务器收到SYN请求后&a…

《探索 C++:一门强大且多功能的编程语言》

《探索 C&#xff1a;一门强大且多功能的编程语言》 在编程的广阔世界里&#xff0c;C 无疑是一颗璀璨的明星&#xff0c;它以其高性能、丰富的特性和广泛的应用领域&#xff0c;吸引着无数开发者投身其中。今天&#xff0c;就让我们一同深入探索一下这门令人着迷的编程语言吧。…

设计模式-创建型-抽象工厂模式

1.概念 工厂方法模式只能生产一个产品系列&#xff0c;抽象工厂可以生产多个产品系列 2.作用 多个具体产品组成一个产品族&#xff08;产品系列&#xff09;&#xff0c;一个具体工厂负责生产一个产品族 3.应用场景 系统所需产品间由依赖关系&#xff0c;可以划分为同一产…

PostgreSQL中的内存上下文管理

在数据库的世界里&#xff0c;内存管理是性能优化的关键。PostgreSQL&#xff0c;作为一个高级的开源对象关系数据库系统&#xff0c;拥有一套精细的内存上下文管理系统&#xff0c;它不仅提高了数据库的性能&#xff0c;还增强了系统的稳定性。本文将深入探讨PostgreSQL中的内…

C++ 中的类型别名和 using 声明及其如何使用。

类型别名 类型别名允许为已存在的类型创建一个新的名称&#xff0c;这在处理复杂的类型表达式时特别有用&#xff0c;可以使代码更清晰、更易于理解。类型别名的定义可以通过两种方式实现&#xff1a; 使用typedef关键字‌&#xff1a; typedef int Integer; Integer a 10; /…