Skip to content

35.1 Docker 环境持续部署

35.1.1 关于全 Docker 环境部署

利用拥有 .NET 环境的 Jenkins,进行持续化部署

35.1.2 安装 DockerJenkins

正常在 Docker 中拉取的 Jenkins:lts 是无法执行 dotnet 命令的(就算你宿主机有 dotnet 环境、docker 中也有 dotnet 环境也不可以), 所以我们只能构建一个包含 dotnet 的镜像

35.1.2.1 使用 Dockerfile 制作镜像

使用 Dockerfile 创建包含 dotnetJenkins 镜像

  • 👉 编写 Dockerfile
# 封装Jenkins镜像(带有dotnet环境的) sdk=5.1  
FROM jenkins/jenkins:lts  
USER root  
WORKDIR /dotnet  
RUN apt-get update && apt-get install -y wget && rm -rf /var/lib/apt/lists/*  
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 -a | 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 -a | 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