使用 Gitlab CI/CD 实现自动化发布站点到 IIS

C#

浏览数:606

2019-5-10

说明

这里先介绍下两个东西 CI/CDGitLab Runner,当然在此之前你需要对 git 有所了解,关于 git 这里不做说明,可以自行百度。

首先介绍 CI/CD :随着我们开发方式的转变,程序的发布变得非常频繁,而其这些发布操作都是重复的。CI/CD 就是为了使这些操作能变得自动化,那它是怎么实现自动化的呢?其实它做的就是当我们使用 git push(推送)代码的时候会执行 任务(task) 而这个 任务 里面其实又包含多个 作业(job),如对代码进行单元测试、部署项目等等,这些 任务作业 在 gitlab 中其实是以一个 .gitlab-ci.yml 文件存在的,这个文件后面会说明。好了我们知道了 CI/CD 是什么(心虚~,你们可以自行百度查看更详细的说明。),那么到底是谁在执行这些 任务作业 的呢?这就是下面要介绍的 GitLab Runner

GitLab Runner:GitLab Runner 就是用来运行我们定义好的 任务作业 也就是 .gitlab-ci.yml 文件。Runner 分为 Shared Runner(共享型) 和 Specific Runner(专有型),Shared Runner 是所有的项目都能用,但只能由管理员创建,而 Specific Runner(专有型)只能为指定的项目服务。Shared Runner 一般是用在有多个项目的服务器上,Specific Runner 则是单个项目的服务器,或者是你自己的电脑上。

下面列出我本次使用的环境:

操作系统:Windows 10
项目版本:.NET Core 2.2
脚本执行环境:PowerShell 5.1.17763.316
Web服务器:IIS 10.0
Gitlab:使用 gitlab.com (*Gitlab 支持私有化部署 )

项目地址:https://gitlab.com/WigorRunnerTest

Gitlab CI/CD

首先你需要在 GitLab 上注册个账号,这里需要使用你懂的工具上网,因为它使用了谷歌的 reCAPTCHA,如果你是自己部署的 gitlab 将没有这个问题。如果大家有需要请留下邮箱。

Gitlab 设置中文界面

Gitlab 默认的界面是英文的,只需要点击头像行的 Settings,然后点击 左侧导航栏Preferences,之后在滑到最底部找到 Localization 旁边的 Language 选择 简体中文,最后点击 Save changesF5 刷新页面即可。

查看设置中文教程

设置好后我们可能更方便的操作 gitlab 了,接着我们需要创建一个项目,这里将使用一个 DotNET Core 项目为例。创建好项目后我们需要将它先 clone 到本地。

下载 Gitlab Runner

在我们定义 任务作业 之前我们需要在我们的服务器或者是电脑上安装好 Gitlab Runner

官网下载地址:https://docs.gitlab.com/runner/install/

下面是我整理好的下载地址,本次使用的是 Windows amd64

Windows: 下载x86下载amd64

下载好后,找到你下载的目录,将软件重命名为 gitlab-runner.exe。只用使用 cmd 进入到该目录,需要注意的是你需要以 管理员 的方式运行 cmd,否者后面执行命令的时候会报错。

注册 Gitlab Runner

接着在命令行中输入:

gitlab-runner register

这时会出现提示:Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):

它叫你输入协调器的地址,这个地址是在你 gitlab 项目的 左侧导航栏设置 下的 CI/CD 中,找到 Runner 点击展开,就会看到 专有Runner共享Runner ,这里我们使用 专有Runner 做演示说明。红色框中的东西是我们后面需要用到的东西。

好了我们有了 coordinator URL 把它复制下了,粘贴到刚刚的命令中回车。

出现了另外一个提示:Please enter the gitlab-ci token for this runner:,需要你输入 token ,这个 token 就是你刚刚复制 URL 下面的 注册令牌。接着它要你输入这个 Runner 的描述,这个根据自己的情况填。

之后又来一个提示:Please enter the gitlab-ci tags for this runner (comma separated):,需要我们输入 Runner 的标签,这里我使用 deploy。

最后一个提示:Please enter the executor: docker, virtualbox, shell, ssh, docker+machine, docker-ssh+machine, kubernetes, docker-ssh, parallels:,需要我们填入脚本的执行环境,这里先填 shell,这时你的 gitlab-runner.exe 下会生成一个 config.toml 文件,里面保存着我们刚刚输入的信息。

需要注意的是这个标签就是我们后面编写 .gitlab-ci.yml 里的 job 会用到,它根据 tags 来指派哪些 Runner 会执行该 任务作业

之后我们回到 gitlab 可以看到这里已经有个激活的运行器了,这里的图标也变成了绿色。如果你这里显示的不是绿色,那么你刷新下页面看看,还不行的话那么你需要运行 gitlab-runner restart 命令来重启 Runner,接着可以使用 gitlab-runner status 查看 Runner 的运行状态。出现 gitlab-runner: Service is running! 那么表示你的服务已经运行成功了。 再次强调你的命令需要使用 管理员 身份运行。

将 Shell 改成 PowerShell

上面选择脚本执行环境的时候我们选了 shell,但是本次我是在 Windows 环境下运行,所以需要将它改为 PowerShell,打开 config.toml 文件,在 [[runners]] 下加入 shell = "powershell" ,然后保存文件即可。

.gitlab-ci.yml 简单说明

上面已经提过 .gitlab-ci.yml 使用来干什么的了,.gitlab-ci.yml 其实是本次自动化发布的核心,它是放在你 gitlab 上项目的根目录下。这里将对 .gitlab-ci.yml 该怎么配做一个简单说明,我只会介绍我用的东西更多的东西你可以查看我下面的「相关文档」。

首先在项目根目录下建立一个 .gitlab-ci.yml 文件,代码如下:

before_script:
  - cd src
stages:
  - test

# job
test:
  stage: test
  # 将会执行的脚本
  script:
    - dotnet restore
    - dotnet build
  # 哪个分支会执行
  only:
    - master
    #runner 注册时的 tag,这里指会触发的 runner
  tags:
    - deploy

我们来一个个说明这些东西的作用:

before_script 在整个项目 clone 到 Runner 所处的服务器时会先执行这个里面的脚本,这里我是进入到了 src 目录,你还可以在这里面做一些包还原的操作。

stages 里放的是将会执行的 job。

test 是做作业(job),这个命名你可以根据自己的情况来。test 就是上面 stages 会执行的 job 的真正配置处。

  1. stage 对应 stages 中的项,如果一个 job 没有指定 stage,那么这个任务会分配到test stage。

  2. script 就是执行的脚本,构建自动化的核心也就是在此处。作为简单的演示,我就还原了包和生成项目。

  3. only 是值该 job 会在被哪些分支 push 触发。

  4. tags 上面在我们注册时有提到过,这个 tags 对应的是我们注册 gitlab runner 时所填的 tages,表示的是该 job 会触发哪些 Runner。

OK,我们此时已经将一个最简单的 .gitlab-ci.yml 构建好了,在项目根目录下执行 git commit -am "[init] .gitlab-ci.yml"git push,将配置好的文件 push(推送)到远端。回到 gitlab 中,我们点击 CI/CD 可以看到有一个流水线在运行。

点进去可以看到运行的日志,可以看到我们 before_scriptscript 中的命令在一条条的执行,当然如果你的脚本出现了错误,状态会是 失败,你需要检查你的脚本是否有误。如果你的状态一直处于 等待中 那么需要检查你的 gitlab runner 是否允许正常,以及上面提到的 设置 中的 Runner 是否处于激活状态(绿色图标)。

输出乱码问题解决

你可能发现了这里怎么有一些奇怪的字符,这是因为我的操作系统是中文,乱码了解决办法是在 before_script 加入 - chcp 65001 脚本。

再次提交代码,ok 这次的中文信息显示正确了。

变量作用的说明

.gitlab-ci.yml 是存放在我们项目的根目录下的,如果我们项目使开源的,那么我们将会暴露一些私密信息如token,密钥,项目发布所处服务器的路径,这些信息公开可能会使我们的项目存在安全隐患。亦或者我们需要部署多个项目但是它们的 .gitlab-ci.yml 文件十分相似那么我们就可以通过变量控制哪些可变的因素。

那么到底怎么使用变量呢?第一步我们需要先声明变量,在 gitlab 的项目中找到 设置 下的 CI/CD,可以看到 变量 然后展开,这里就是可以声明我们需要用到的变量。.gitlab-ci.yml 只需要在脚本需要用到变量的方法使用 $env:变量名 的形式使用即可,需要注意的是:不同的系统使用变量的方法也不一样,这里我使用是 PowerShell。

常用的变量使用方法:

Shell 使用方法
bash/sh $variable
windows batch %variable%
PowerShell $env:variable

关于变量的更多说明可以参考官方的文档:http://192.168.20.21/help/ci/variables/README#variables

自动化部署到 IIS

前面已经介绍了构建一个自动化的流程,有了前面的基础其实自动化部署到 IIS 也就是编写的脚本发生了变化。

再开干之前我们需要把我们的思路捋一捋,核心在于怎么通过命令的形式发布一个站点。

  1. 首先需要编译项目,确保代码没有问题
  2. 使用 dotnet publish -c release -r win81-x64 获取我们需要发布站点的部署文件
  3. IIS 停止运行需要发布的站点
  4. IIS 停止该站点的进程池
  5. 备份原有项目(不是必须,但是最好不要省去该步骤)
  6. 删除 IIS 上需要发布的站点的原有文件
  7. 复制我们准备好发布的文件(也就是 publish 文件夹)到 IIS 站点下
  8. IIS 启动进程池
  9. IIS 启动该站点

下面一步一步已脚本的形式来说明:

  1. 首先确定整体的东西,这里我准备构建两个 job testdeploy,第一个 job 用于校验我们的代码是否正确,第二个是部署的 job。第一个 job 只有两行命令,还原和编译。
before_script:
  #中文乱码问题
  - chcp 65001
  - cd src

# 执行的 job 
stages:
  - test
  - deploy

# 校验代码
test:
  stage: test
  # 将会执行的脚本
  script:
    - dotnet restore
    - dotnet build
  # 哪个分支会执行
  only:
    - master
    #runner 注册时的 tag,这里指会触发的 runner
  tags:
    - deploy

# 部署
deploy:
  stage: deploy
  # 将会执行的脚本
  script:

  # 哪个分支会执行
  only:
    - master
  #runner 注册时的 tag,这里指会触发的 runner
  tags:
    - deploy
  1. 在进行编写剩下的脚本之前需要定义几个变量:
    ProjectName:项目名称,用于 publish 用,如 VS 下一个解决方案可能存在多个项目,这时候就需要知道我们 publish 的项目使哪个。
    WebSiteName:站点名称,用户关闭 IIS 站点和 IIS 对应进程池的,如果你的进程池和站点的名称不一致请在声明一个变量。
    WebSitePath:站点的路径,用于备份、删除原有站点、新的项目复制到该路径下。

定义好这些变量后接着写我们 deploy 的脚本:
可以看到这里使用了:$env:ProjectName$env:WebSitePath$env:WebSiteName 变量。

# 部署
deploy:
  stage: deploy
  # 将会执行的脚本
  script:

    # 声明一个变量保存当前时间,用作备份数据文件夹名称
    - $datetime=Get-Date -Format 'yyyy-MM-dd-HH-mm'
    # 编译打包项目
    - dotnet publish -c release -r win81-x64
    # 进入编译好的项目目录
    - cd $env:ProjectName\bin\Release\netcoreapp2.2\win81-x64\
    # 停止 IIS 对应站点
    - C:\Windows\System32\inetsrv\appcmd.exe stop site $env:WebSiteName
    # 停止进程池
    - C:\Windows\System32\inetsrv\appcmd.exe stop apppool /apppool.name:"$env:WebSiteName"
    # 备份原有项目文件,项目名_当前时间
    - cp "$env:WebSitePath" "$env:WebSitePath$datetime" -Recurse
    # 删除原有站点
    - del "$env:WebSitePath" -Recurse
    #复制 publish 文件到站点
    - cp "publish" "$env:WebSitePath" -Recurse
    # 启动进程池
    - C:\Windows\System32\inetsrv\appcmd.exe start apppool /apppool.name:"$env:WebSiteName"
    # 启动 IIS 站点
    - C:\Windows\System32\inetsrv\appcmd.exe start site $env:WebSiteName
  
  # 哪个分支会执行
  only:
    - master
  #runner 注册时的 tag,这里指会触发的 runner
  tags:
    - deploy

到这一步整个自动化发布已经完成了,我们只要 push 代码到远端就会自动部署我们的项目到 IIS 中,需要注意的是你必须确保你的 IIS 中已经有这个站点了。

回到 gitlab 中查看 CI/CD 可以看到这次我们的阶段有两个,因为我配置了两个 作业(job),一个 test一个 deploy。

点击每个作业中看看执行的脚本是不是我们定义好的,需要提一下 powershell 脚本如果出错的话 gitlab-ci 返回的结果还是会显示成功,错误提示还是乱码的,坑啊。额~目前还找到解决的办法,如果是 docker 或者 linux 下应该没有这问题。

再看看 IIS 这边的效果,文件已经自动备份了,站点也正常运行了,一个自动化部署项目到 IIS 站点已经完成了。

模拟项目发布

下面修改代码然后 push 上去看看,看看我们的网站没有没有更新。

完整的 .gitlab-ci.yml

before_script:
  #中文乱码问题
  - chcp 65001
  - cd src

# 执行的 job 
stages:
  - test
  - deploy

# 校验代码
test:
  stage: test
  # 将会执行的脚本
  script:
    - dotnet restore
    - dotnet build
  # 哪个分支会执行
  only:
    - master
    #runner 注册时的 tag,这里指会触发的 runner
  tags:
    - deploy

# 部署
deploy:
  stage: deploy
  # 将会执行的脚本
  script:
    # 声明一个变量保存当前时间,用作备份数据文件夹名称
    - $datetime=Get-Date -Format 'yyyy-MM-dd-HH-mm'
    # 编译打包项目
    - dotnet publish -c release -r win81-x64
    # 进入编译好的项目目录
    - cd $env:ProjectName\bin\Release\netcoreapp2.2\win81-x64\
    # 停止 IIS 对应站点
    - C:\Windows\System32\inetsrv\appcmd.exe stop site $env:WebSiteName
    # 停止进程池
    - C:\Windows\System32\inetsrv\appcmd.exe stop apppool /apppool.name:"$env:WebSiteName"
    # 备份原有项目文件,项目名_当前时间
    - cp "$env:WebSitePath" "$env:WebSitePath$datetime" -Recurse
    # 删除原有站点
    - del "$env:WebSitePath" -Recurse
    - cp "publish" "$env:WebSitePath" -Recurse
    # 启动进程池
    - C:\Windows\System32\inetsrv\appcmd.exe start apppool /apppool.name:"$env:WebSiteName"
    # 启动 IIS 站点
    - C:\Windows\System32\inetsrv\appcmd.exe start site $env:WebSiteName
  
  # 哪个分支会执行
  only:
    - master
  #runner 注册时的 tag,这里指会触发的 runner
  tags:
    - deploy

小结

至此已经实现了 push 时项目自动发布到 IIS 。当然在这个过程中踩了 n 多的坑,总结要细心安装步骤一步一步认真的走。下一步准备对接钉钉的机器人。实现的效果是当我们项目发布时会自动通知,发布成功后也会自动通知。

相关文献

《什么是 CI/CD?》:https://linux.cn/article-9926-1.html

《GitLab-CI与GitLab-Runner》: http://www.cnblogs.com/cnundefined/p/7095368.html

《IIS 站点和进程池关闭》:https://www.cnblogs.com/jmaly/p/9860606.html

《Gitlab-CI job 配置文件 .gitlab-ci.yml 配置方式(翻译)》:https://blog.csdn.net/kunyus/article/details/81390330

powershell论坛:https://www.pstips.net

GitLab Runner 官方文档:https://docs.gitlab.com/ee/ci/runners/README.html

作者:AMortal