35.1 Docker 环境持续部署
35.1.1 关于全 Docker
环境部署
利用拥有 .NET
环境的 Jenkins
,进行持续化部署
35.1.2 安装 Docker
版 Jenkins
正常在 Docker
中拉取的 Jenkins:lts
是无法执行 dotnet
命令的(就算你宿主机有 dotnet
环境、docker
中也有 dotnet
环境也不可以),
所以我们只能构建一个包含 dotnet
的镜像
35.1.2.1 使用 Dockerfile 制作镜像
使用 Dockerfile
创建包含 dotnet
的 Jenkins
镜像
- 👉 编写
Dockerfile
# 封装Jenkins镜像(带有dotnet环境的) sdk=5.1
FROM jenkins/jenkins:lts
USER root
WORKDIR /dotnet
RUN wget -O dotnet.tar.gz https://download.visualstudio.microsoft.com/download/pr/820db713-c9a5-466e-b72a-16f2f5ed00e2/628aa2a75f6aa270e77f4a83b3742fb8/dotnet-sdk-5.0.100-linux-x64.tar.gz
RUN tar zxf dotnet.tar.gz -C ./
RUN rm -rf dotnet.tar.gz
ENV PATH="${PATH}:/dotnet:/var/jenkins_home/.dotnet/tools"
ENV DOTNET_ROOT="/dotnet"
RUN apt update -y
RUN apt install icu-devtools vim zip unzip -y
RUN usermod -a -G root jenkins
USER jenkins
- 👉 命令解释
- 1. 这个Docker镜像基于jenkins
- 2. 设置当前用户为root,因为后面安装需要使用root
- 3. 设置当前工作目录为dotnet
- 4. 下载dotnet SDK包,保存为dotnet.tar.gz。这里要注意下载正确版本的SDK,可前往微软官方网站获取下载链接:https://dotnet.microsoft.com/download
- 5. 解压dotnet SDK到当前目录,即/dotnet目录
- 6. 删除dotnet SDK包
- 7. 把dotnet目录和dotnet tools目录添加到环境变量PATH,这样就可以使用dotnet命令了
- 8. 设置DOTNET_ROOT变量
- 9. 更新源
- 10. 安装一些必需的,常用的工具包,其中icu-devtools是运行dotnet需要的
- 11. 修改jenkins用户到root附加组
- 12. 设置当前用户为jenkins
- 👉 构建
Docker
镜像name=jenkins:dotnet
cd
到根目录下(必须含 Dockerfile
) 只需构建命令:
docker build -t jenkins:dotnet .
特别注意
结尾 .
不能省略
35.1.2.2 运行 Jenkins:dotnet
镜像
docker run -d -p 8080:8080 -p 50000:50000 --name mjenkins \
--privileged=true \
--restart always \
-u root \
-e TZ="Asia/Shanghai" \
-v /mudata/jenkins:/var/jenkins_home \
-v /usr/bin/docker:/usr/bin/docker \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /mudata/webroot/:/mudata/webroot \
jenkins:dotnet
接下来就是比较俗套的安装 Jenkins
步骤,网上资料很多,不展开了。
35.1.3 Jenkins
的自动化部署
35.1.3.1 编写 Shell 脚本
# Jenkins 构建 测试服
echo '============查看打包环境================'
pwd
ls
echo $PATH
image_version=`date +%Y%m%d%H%M`;
echo $image_version;
dotnet --info
dotnet --version
# 获取短版本号
GITHASH=`git rev-parse --short HEAD`
echo '============================begin restore======================================='
dotnet restore
echo '============================end restore======================================='
#要构建的解决方案名称
solutionName=MUSaas.SCM.BasicData
#docker run的容器名称
containerName=jenkinsscmbasic
#指定run的端口
port=9994
#.sln文件全路径
#solutionDir=20-Solution/${solutionName}.sln
#.csproj文件全路径
csprojDir=${solutionName}/${solutionName}.csproj
#项目发布的目录
webDir=/mudata/webroot/jenkins/publish/webapp
#归档目录
archivesDir=/mudata/webroot/jenkins/publish/archives
#清空文件夹
rm -rf ${webDir}/${JOB_NAME}/*
#发布网站到webDir
dotnet publish ${JENKINS_HOME}/workspace/${JOB_NAME}/${csprojDir} -c Release -o ${webDir}/${JOB_NAME} /p:Version=1.0.${BUILD_NUMBER}
#复制配置文件
#cp -rf /vdb1/jenkins/DotNetCoreWebPublishToDockerCommonConfigs/* ${webDir}/${JOB_NAME}/
#判斷是否存在
CID=$(docker ps | grep "${containerName}" | awk '{print $1}')
echo $CID
if [ "$CID" != "" ];then
docker stop ${containerName}
docker rm ${containerName}
docker rmi ${containerName}
#docker stop $CID
#docker rm $CID
fi
#通过Dockerfile重新构建镜像
docker build -t ${containerName} ${webDir}/${JOB_NAME}/.
#docker run容器并绑定到端口
#docker run -d -p ${port}:80 --name ${containerName} ${containerName}
docker run --name ${containerName} --restart=always -d -p ${port}:${port} -v /etc/localtime:/etc/localtime:ro ${containerName}
echo "success!"
就这样自动化部署就好了。 测试服的
Jenkins
将源码拉下来,Publish,Docker Build,Docker Run
。
这里想要发布的时候,每次都需要手动去点击“构建”才会执行。也可以做成当分支合并成功后自动运行。反正
Jenkins
装好之后,你想要什么都能玩起来。比如指定分支提交后自动“构建”、比如构建成功后合并到 Master 等等
35.1.4 Jenkins
的自动化远程部署
35.1.4.1 安装插件
Publish Over SSH
35.1.4.2 配置
系统管理 =>
Publish over SSH
35.1.4.3 写脚本
# Jenkins 构建 正式服
echo '============查看打包环境================'
pwd
ls
echo $PATH
image_version=`date +%Y%m%d%H%M`;
echo $image_version;
dotnet --info
dotnet --version
# 获取短版本号
GITHASH=`git rev-parse --short HEAD`
echo '============================begin restore======================================='
dotnet restore
echo '============================end restore======================================='
#要构建的解决方案名称
solutionName=MUSaas.SCM.BulkOrder
#docker run的容器名称
containerName=jenkinsscmbulk
#指定run的端口
port=9986
#.csproj文件全路径
csprojDir=/${solutionName}/${solutionName}.csproj
#项目发布的目录
webDir=/mudata/webroot/jenkins/publish/webapp
#归档目录
archivesDir=/mudata/webroot/jenkins/publish/archives
#清空文件夹
rm -rf ${webDir}/${JOB_NAME}/*
#发布网站到webDir
dotnet publish ${JENKINS_HOME}/workspace/${JOB_NAME}/${csprojDir} -c Release -o ${webDir}/${JOB_NAME} /p:Version=1.0.${BUILD_NUMBER}
#复制配置文件
#cp -rf /vdb1/jenkins/DotNetCoreWebPublishToDockerCommonConfigs/* ${webDir}/${JOB_NAME}/
#构建远程包
rm -rf ${JENKINS_HOME}/workspace/${JOB_NAME}/publish
mkdir ${JENKINS_HOME}/workspace/${JOB_NAME}/publish
tar -czvf ${JENKINS_HOME}/workspace/${JOB_NAME}/publish/${JOB_NAME}.${BUILD_NUMBER}.tar.gz -C ${webDir}/${JOB_NAME} .
echo "success!"
大概逻辑就是发布后,打个包。然后丢给远程,远程再执行
shell
注意这里一定要发布到自己的
workspace
下,防止下一步死活找不到位置。如果找不到位置,只能慢慢用ls
命令,一级一级去测,很麻烦
35.1.4.4 构建后操作(关键)
选择 Send Build artifacts over SSH
Source files: publish/
Remove prefix(不填)
Remote directory:/mudata/webroot/publish/
Exec command:bash /mudata/shell/publish.sh ${JOB_NAME} jenkinsscmbase ${JOB_NAME}.${BUILD_NUMBER} 9994
- 选择自己的 SSH 服务器
Source files
:一定是workspace
下的地址Remote directory
:远程地址,从根目录开始Exec command
:要执行的 shell。这里所有的Jenkins
环境变量都可以用
35.1.4.5 远程执行
publish.sh
# Jenkins Prod服 调用脚本
solutionName=$1
containerName=$2
filename=$3
port=$4
#.publis
echo ${solutionName}
echo ${containerName}
echo ${filename}
baseDir=/mudata/webroot/publish
webDir=${baseDir}/publish/${filename}
rm -rf ${webDir}
mkdir ${webDir}
tar -zxvf ${baseDir}/publish/${filename}.tar.gz -C ${webDir}/
rm -f ${webDir}/appsettings.json && mv ${webDir}/appsettings.Prod.json ${webDir}/appsettings.json
#判斷是否存在
CID=$(docker ps | grep "${containerName}" | awk '{print $1}')
echo $CID
if [ "$CID" != "" ];then
docker stop ${containerName}
docker rm ${containerName}
docker rmi ${containerName}
#docker stop $CID
#docker rm $CID
fi
cd ${webDir}/ && docker build -t ${containerName} .
docker run --name ${containerName} --restart=always -d -p ${port}:${port} --link myredis:myredis -v /etc/localtime:/etc/localtime:ro ${containerName}
这里的逻辑就是解压,然后
Docker
相关。每次构建都是带着版本号来的。
35.1.5 反馈与建议
与我们交流
给 Furion 提 Issue。