一、安装jenkins
- 直接war包搭建下载地址:https://get.jenkins.io/war-stable/
下载稳定长期版本
二、jenkins 启动依赖java, 安装java sdk ,好像支持java 11和17版本,21版本不支持会报错
- 下载sdk地址,https://www.oracle.com/java/technologies/downloads/#java17
- 解压并且添加环境变量
sh
tar -xzf jdk-17_linux-x64_bin.tar.gz -C /usr/local/
在/etc/profile 添加
export JAVA_HOME=/usr/local/jdk-17.0.8
export PATH=$PATH:$JAVA_HOME/bin
source /etc/profile
java -version
三、启动jenkins
1.启动命令
sh
java -jar jenkins.war --httpPort=9090
启动完成后,会生成首次登录的秘钥,一般会在
cat /root/.jenkins/secrets/initialAdminPassword
我使用的github ,在github 配置 ssh 公钥 ,位置setting ssh,在jenkins 配置全局私钥
服务器生成密钥
ssh-keygen -t rsa
注意在页面拉取代码的时候Are you sure you want to continue connecting (yes/no/[fingerprint])? yes,需要点击确认
2.添加到system 守护进程去运行
sh
[Unit]
Description=Jenkins Daemon
After=network.target
[Service]
User=jenkins
Group=jenkins
Type=simple
ExecStart=/usr/local/jdk-17.0.8/bin/java -jar /root/jenkins.war --httpPort=9099
Restart=always
[Install]
WantedBy=multi-user.target
设置启动和开启启动
sudo systemctl daemon-reload
启动 Jenkins: sudo systemctl start jenkins
停止 Jenkins: sudo systemctl stop jenkins
开机启动 Jenkins: sudo systemctl enable jenkins
查看 Jenkins 服务状态: sudo systemctl status jenkins
日志 sudo journalctl -u jenkins
四、继续安装docker
sh
yum remove docker docker-common docker-selinux docker-engine
yum install -y yum-utils device-mapper-persistent-data lvm2
选择镜像
阿里云镜像
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
源镜像
yum-config-manager --add-repo http://download.docker.com/linux/centos/docker-ce.repo
调试容器出错原因
docker run -it --rm -p 8062:8062 \
-v $(pwd)/config.yaml:/app/conf/config.yaml \
-v $(pwd)/logs:/app/logs \
gitxuzan/weather_api:v0.0.1 /bin/sh
sh
查看服务端:
yum list docker-ce --showduplicates | sort -r
选择版本安装
查看客户端,下载对应版本
yum list docker-ce-cli --showduplicates | sort -r
yum install -y docker-ce-3:20.10.9-3.el8 docker-ce-cli-1:20.10.9-3.el8
最后开启启动查看
systemctl start docker
systemctl enable docker docker version
五、设置跳板机登录
.ssh/config文件配置
执行 ssh target 可以跳板机登录
# 定义跳板机 (a) 的配置
Host bastion
# 跳板机的IP地址或主机名
HostName 16.xxx.xxx.xx
# 用于登录跳板机的用户名
User xuzan
# Jenkins 服务器上的SSH私钥路径,用于身份验证
IdentityFile /var/lib/jenkins/.ssh/bastonhost_16.xxx.xxx.pem
# 定义目标服务器 (b) 的配置
Host target
# 目标服务器的IP地址或主机名
HostName 52.xxx.xxx.xxx
# 用于登录目标服务器的用户名
User ec2-user
# Jenkins 服务器上的SSH私钥路径,用于身份验证
IdentityFile /home/xuzan/.ssh/news_app.pem
# 使用ProxyCommand来指定通过跳板机连接到目标服务器
# 这里使用ssh命令通过跳板机连接到目标服务器
ProxyCommand ssh -q -W %h:%p bastion
六、jenkins 流水线,监听到push,然后根据commit 信息打包
sh
pipeline {
agent any
options {
disableConcurrentBuilds() // 确保流水线不会并行执行
timeout(time: 5, unit: 'MINUTES') // 设置整个流水线的超时为 5 分钟
}
environment {
CRAWLER_API = "weather_api"
DIR_RUN = "cd /home/ec2-user/data/docker/services/weather && ./secrets.sh"
CREDENTIALSID = "f2b9ffa0-89d4-41bd-b3b4-9d5fd3cfac06"
VERSION_FILE = 'deployed_version.txt'
}
stages {
stage('Retrieve Latest Successful Version') {
steps {
script {
if (fileExists(env.VERSION_FILE)) {
def versions = readFile(file: env.VERSION_FILE).trim().split("\n")
env.LATEST_VERSION = versions[-1] // Last line is the latest version
env.PREVIOUS_VERSION = versions.size() > 1 ? versions[-2] : "v0.0.1" // Second last line is the previous version
} else {
env.LATEST_VERSION = "v0.0.1"
env.PREVIOUS_VERSION = "v0.0.1"
}
}
}
}
stage('Checkout Code from GitHub') {
steps {
checkout([
$class: 'GitSCM',
branches: [[name: '*/main']],
extensions: [],
userRemoteConfigs: [[url: "git@github.com:xxxxx/${CRAWLER_API}.git", credentialsId: "${CREDENTIALSID}"]]
])
}
}
stage('Decide Operation Based on Commit Message') {
steps {
script {
def lastCommitMessage = sh(script: "git log -1 --pretty=%B", returnStdout: true).trim()
env.CommitMessage = lastCommitMessage
if (lastCommitMessage.startsWith("#pro")) {
env.OPERATION = "deploy"
env.VERSION = "v0.0.${env.BUILD_NUMBER}"
} else if (lastCommitMessage.startsWith("#pre")) {
env.OPERATION = "rollback"
env.VERSION = env.PREVIOUS_VERSION
} else {
currentBuild.result = 'ABORTED'
error("Invalid commit message. Either start with #pro for deploy or #pre for rollback!")
}
}
}
}
stage('Build Docker Image and Push') {
when {
expression { env.OPERATION == "deploy" }
}
steps {
script {
sh 'docker build --platform linux/amd64 -t xxxx/${CRAWLER_API}:${VERSION} -f Dockerfile_amd64_arm64 .'
sh 'docker push xxxx/${CRAWLER_API}:${VERSION}'
}
}
}
stage('登录服务器Deploy/Rollback on Production Server') {
steps {
script {
sh 'ssh -t target "${DIR_RUN} ${VERSION}"'
}
}
}
stage('验证接口Verify Deployment') {
steps {
script {
sleep 5
sh """
status_code=\$(curl -o /dev/null -s -w "%{http_code}" https://xxxxx/weather/v1/app/test)
if [ "\$status_code" != "200" ]; then
echo "API check failed! Received status code: \$status_code"
exit 1
fi
"""
}
}
}
}
post {
success {
echo 'Build was successful!'
script {
if (env.OPERATION == "deploy") {
// 如果文件存在且最后一个字符不是换行符,则追加一个换行符
if (fileExists(env.VERSION_FILE) && sh(script: "tail -c 1 ${env.VERSION_FILE} | wc -l", returnStdout: true).trim() != "1") {
sh "echo '' >> ${env.VERSION_FILE}"
}
// 追加版本号
sh "echo '${VERSION}' >> ${env.VERSION_FILE}"
}
currentBuild.description = "构建成功!"
def projectName = sh(script: "basename `git rev-parse --show-toplevel`", returnStdout: true).trim()
def messageToSend = "${projectName}: ${VERSION} ${env.CommitMessage}"
sh "ssh target '/home/ec2-user/data/docker/services/tg.sh \"构建成功 ${messageToSend}\"'"
}
}
failure {
echo 'Build failed!'
script {
currentBuild.description = "构建失败!"
def projectName = sh(script: "basename `git rev-parse --show-toplevel`", returnStdout: true).trim()
def messageToSend = "${projectName}: ${VERSION} ${env.CommitMessage}"
sh "ssh target '/home/ec2-user/data/docker/services/tg.sh \"构建失败 ${messageToSend}\"'"
}
}
aborted {
echo '构建取消拉aborted!'
script {
currentBuild.description = "构建取消拉!"
}
}
}
}
获取构建方式,例如是push 的还是手动构建的,还是定时构建的
environment {
CAUSE = "${currentBuild.getBuildCauses()[0].shortDescription}"
}
其他
github clone不下来
https://ping.chinaz.com/github.com
选择可用的ip ,在/etc/hosts 修改
20.205.243.166 github.com
20.205.243.166 raw.githubusercontent.com