<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>cd on 青云卷</title><link>https://mydream.ink/tags/cd/</link><description>Recent content in cd on 青云卷</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>Copyright © 2018–2023</copyright><lastBuildDate>Sun, 08 Sep 2019 18:37:36 +0800</lastBuildDate><atom:link href="https://mydream.ink/tags/cd/index.xml" rel="self" type="application/rss+xml"/><item><title>自动化运维之自动构建</title><link>https://mydream.ink/posts/devops/auto-devops-auto-build/</link><pubDate>Sun, 08 Sep 2019 18:37:36 +0800</pubDate><guid>https://mydream.ink/posts/devops/auto-devops-auto-build/</guid><description>&lt;p>本文供自己记录学习，我会尽量保证文章准确无误，但因本人水平有限，如果不幸产生任何错误，望读者不吝赐教。&lt;/p>
&lt;h2 id="浅析-gitlab-runner-相关配置">浅析 gitlab-runner 相关配置&lt;/h2>
&lt;p>在 gitlab-runner 中每个 runner 都需要指定 &lt;a href="https://docs.gitlab.com/runner/executors/">executor&lt;/a>，executor 有以下几种类型：&lt;/p>
&lt;ul>
&lt;li>SSH&lt;/li>
&lt;li>Shell&lt;/li>
&lt;li>Parallels&lt;/li>
&lt;li>VirtualBox&lt;/li>
&lt;li>Docker&lt;/li>
&lt;li>Docker Machine (auto-scaling)&lt;/li>
&lt;li>Kubernetes&lt;/li>
&lt;li>Custom&lt;/li>
&lt;/ul>
&lt;p>我们会将 gitlab-runner 部署在 kubernetes 集群中，所以此处选用 kubernetes 作为 executor。有关该 executor 的配置方式，在&lt;a href="https://docs.gitlab.com/runner/executors/kubernetes.html">官方文档&lt;/a>中有详细说明，此处就此次配置所需要的进行简单说明，其它的再视情况进行补充。&lt;/p>
&lt;p>与其它类型的 executor 一样，kubernetes 也需要根据 gitlab 仓库的 url 和 token 对 runner 进行注册方可使用。注册后会有一个常驻的 pod （我姑且叫它 runner 服务端）对来自于 gitlab 的 pipeline 任务进行监听，当监听到有新的任务需要执行时，就会创建新的 pipeline 跑 &lt;code>.gitlab-ci.yml&lt;/code> 上对应的job。所以 runner 服务端相关联的 ServieAccount 一定需要具备对应的 namespace 的 pod 的创建的权限。&lt;/p>
&lt;p>配置一个 runner 有多种方式，包括启动参数、环境变量、配置文件等。这其中配置文件的功能最强，参数可配置项较环境变量稍多（或许它们具有相同的能力，只是我没有发现，如果你知道欢迎帮忙补充）。通过&lt;code>gitlab-runner help register&lt;/code>命令我们可以找到所有的启动参数和环境变量，参数与环境变量之间的关系请参照&lt;a href="https://gist.github.com/alphajc/e2c19fa624ccc29fb3af0803e9afcb22">参数与环境变量对照表&lt;/a>。&lt;/p>
&lt;h3 id="runner-的集群中权限">runner 的集群中权限&lt;/h3>
&lt;p>前面已经谈到 runner 服务端在注册成功监听到新的任务后，需要以 Pod 的形式创建 Worker 对新对任务进行处理。这里我们需要考虑几种权限：Pod 的操作权限、Worker 镜像的拉取权限以及在 Worker 中构建镜像时对私有镜像的拉取权限。&lt;/p>
&lt;p>Pod 的操作权限通过 kubernetes 中的 ServiceAccount 来实现，我们需要赋予对应的 ServiceAccount 对指定命名空间的 Pod 的操作权限，相关的参数有&lt;code>--kubernetes-namespace&lt;/code>和&lt;code>--kubernetes-service-account&lt;/code>以及他们环境变量的开关参数&lt;code>--kubernetes-namespace_overwrite_allowed&lt;/code>和&lt;code>--kubernetes-service_account_overwrite_allowed&lt;/code>。这里指定的 ServiceAccount 一定要在指定的 Namespace 中有 Pod 的操作权限，否则 gitlab 在跑 pipeline 的时候会报权限错误。有关 ServiceAccount 的权限配置是通过 RBAC 实现的，详情参照&lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/">kubernetes 中 RBAC 认证的文档&lt;/a>。&lt;/p>
&lt;p>对于 Worker 镜像的拉取权限，一般都是在集群创建时预先配置好的，此处无需另行配置。而 Worker 中构建镜像时对私有镜像的拉取和推送权限是在 &lt;code>.gitlab-ci.yml&lt;/code>中进行配置的，这里不要搞混。&lt;/p>
&lt;h3 id="runner-的持久化存储">runner 的持久化存储&lt;/h3>
&lt;p>runner 可以使用 hostPath 和 PVC 做持久化存储，跟 Kubernetes 中的概念完全一样。用法参照&lt;a href="https://docs.gitlab.com/runner/executors/kubernetes.html#using-volumes">使用卷&lt;/a>，参考配置如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75af00">concurrent&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#ae81ff">4&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">[[&lt;/span>&lt;span style="color:#75af00">runners&lt;/span>&lt;span style="color:#111">]]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># usual configuration&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75af00">executor&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;kubernetes&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#75af00">runners&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">kubernetes&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">[[&lt;/span>&lt;span style="color:#75af00">runners&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">kubernetes&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">volumes&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">host_path&lt;/span>&lt;span style="color:#111">]]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75af00">name&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;hostpath-1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75af00">mount_path&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;/path/to/mount/point&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75af00">read_only&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#00a8c8">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75af00">host_path&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;/path/on/host&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">[[&lt;/span>&lt;span style="color:#75af00">runners&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">kubernetes&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">volumes&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">host_path&lt;/span>&lt;span style="color:#111">]]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75af00">name&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;hostpath-2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75af00">mount_path&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;/path/to/mount/point_2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75af00">read_only&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#00a8c8">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">[[&lt;/span>&lt;span style="color:#75af00">runners&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">kubernetes&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">volumes&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">pvc&lt;/span>&lt;span style="color:#111">]]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75af00">name&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;pvc-1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75af00">mount_path&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;/path/to/mount/point1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">[[&lt;/span>&lt;span style="color:#75af00">runners&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">kubernetes&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">volumes&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">config_map&lt;/span>&lt;span style="color:#111">]]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75af00">name&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;config-map-1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75af00">mount_path&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;/path/to/directory&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#75af00">runners&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">kubernetes&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">volumes&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">config_map&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">items&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;key_1&amp;#34;&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;relative/path/to/key_1_file&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;key_2&amp;#34;&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;key_2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">[[&lt;/span>&lt;span style="color:#75af00">runners&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">kubernetes&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">volumes&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">secret&lt;/span>&lt;span style="color:#111">]]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75af00">name&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;secrets&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75af00">mount_path&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;/path/to/directory1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75af00">read_only&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#00a8c8">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#75af00">runners&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">kubernetes&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">volumes&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">secret&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">items&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;secret_1&amp;#34;&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;relative/path/to/secret_1_file&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">[[&lt;/span>&lt;span style="color:#75af00">runners&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">kubernetes&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">volumes&lt;/span>&lt;span style="color:#111">.&lt;/span>&lt;span style="color:#75af00">empty_dir&lt;/span>&lt;span style="color:#111">]]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75af00">name&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;empty_dir&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75af00">mount_path&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;/path/to/empty_dir&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75af00">medium&lt;/span> &lt;span style="color:#111">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;Memory&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="在-runner-中构建镜像">在 runner 中构建镜像&lt;/h3>
&lt;p>在 runner 中构建 Docker 镜像有两种方式，最常见的是使用&lt;code>docker build&lt;/code>命令，另一种是使用谷歌推出的&lt;a href="https://github.com/GoogleContainerTools/kaniko">&lt;code>kaniko&lt;/code>&lt;/a>。相较于&lt;code>docker build&lt;/code>，&lt;code>kaniko&lt;/code>无需 Docker Daemon 即可工作，因此 Worker 无需在特权模式下工作，这种方式不会挑战 Kubernetes 集群的安全性。下面将具体谈谈两种方式：&lt;/p>
&lt;h4 id="docker-build">docker build&lt;/h4>
&lt;p>使用这种方式构建 Docker 镜像我们不得不为执行该 Job 的 Worker 开启特权模式，这会带来安全性问题。如果你对此不以为然的话，就可以进行接下来的步骤了。&lt;/p>
&lt;p>尽管这种方式本身就是不安全的，但是如果做好以下几点，依然可以有效降低安全风险：&lt;/p>
&lt;ol>
&lt;li>将特权模式的 runner 打上专用标签，仅供使用对应标签的 job 调用；&lt;/li>
&lt;li>创建这种类型的 runner 服务端时，使用 Taint 标记 Node，告诉其它应用这个结点的污点，在部署 runner 或其它可以容忍这个安全问题的应用时设置对应的 Toleration。&lt;/li>
&lt;/ol>
&lt;p>这可以确保特权模式不被滥用，亦可对应用的安全性负责。&lt;/p>
&lt;p>以特权模式运行的&lt;code>docker: dind&lt;/code>容器会在&lt;code>2375/tcp&lt;/code>端口上进行监听，我们可以通过 TCP 协议对 Docker 进行操作。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">image&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#ae81ff">docker:latest&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">variables&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">DOCKER_HOST&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#ae81ff">tcp://localhost:2375&lt;/span> &lt;span style="color:#75715e"># 在 Kubernetes 中 service 会以 sidecar 的形式插到 Pod 中，同一 Pod 中的网络使用 localhost 访问即可&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">DOCKER_DRIVER&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#ae81ff">overlay2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">services&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">docker:18-dind&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">before_script&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">docker login -u &amp;#34;$CI_REGISTRY_USER&amp;#34; -p &amp;#34;$CI_REGISTRY_PASSWORD&amp;#34; $CI_REGISTRY&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">build-master&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">stage&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#ae81ff">build&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">script&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">docker build --pull -t &amp;#34;$CI_REGISTRY_IMAGE&amp;#34; .&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">docker push &amp;#34;$CI_REGISTRY_IMAGE&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>注：docker 宿主机的版本与&lt;code>dind&lt;/code>的版本最好一致。比如我宿主机使用的&lt;code>18.03&lt;/code>的版本，那么镜像就应该使用&lt;code>docker:18-dind&lt;/code>，如果直接使用&lt;code>docker:dind&lt;/code>会使用最新版本的 docker。我当时遇到的一个问题是在 dind 容器中只监听了&lt;code>2376&lt;/code>端口，没有&lt;code>2375&lt;/code>。&lt;code>2376&lt;/code>端口是做了加密的，至少需要配置证书都能使用，&lt;code>2375&lt;/code>端口不能正常使用，不知道是因为版本不一致，还是本来就只会监听&lt;code>2376&lt;/code>，我看 Dockerfile 中，两个端口都有暴露，时间关系我就没有进一步细研了。当我换作&lt;code>docker:18-dind&lt;/code>后，问题都解决了。&lt;/p>
&lt;/blockquote>
&lt;h4 id="kanikohttpsdocsgitlabcomeecidockerusing_kanikohtml">&lt;a href="https://docs.gitlab.com/ee/ci/docker/using_kaniko.html">kaniko&lt;/a>&lt;/h4>
&lt;p>用法如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">build&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">stage&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#ae81ff">build&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">image&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">name&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#ae81ff">gcr.io/kaniko-project/executor:debug&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">entrypoint&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">script&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">echo &amp;#34;{\&amp;#34;auths\&amp;#34;:{\&amp;#34;$CI_REGISTRY\&amp;#34;:{\&amp;#34;username\&amp;#34;:\&amp;#34;$CI_REGISTRY_USER\&amp;#34;,\&amp;#34;password\&amp;#34;:\&amp;#34;$CI_REGISTRY_PASSWORD\&amp;#34;}}}&amp;#34; &amp;gt; /kaniko/.docker/config.json&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">/kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="使用-helm-安装-gitlab-runner">使用 helm 安装 gitlab-runner&lt;/h2>
&lt;p>使用 gitlab 官方 chart 库进行 gitlab-runner 的安装。因为官方的 chart 使用参数和环境变量注册 gitlab-runner，在使用上会有一定的局限性，可能需要一些修改才能进行高级配置。以下是使用官方 chart 部署 gitlab-runner 的步骤：&lt;/p>
&lt;h3 id="前提">前提&lt;/h3>
&lt;ol>
&lt;li>安装了 tiller 的 kubernetes 的集群&lt;/li>
&lt;li>初始化完成了的 helm 命令行工具&lt;/li>
&lt;/ol>
&lt;h3 id="1-添加-gitlab-官方-chart-仓库">1. 添加 gitlab 官方 chart 仓库&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>helm repo add gitlab https://charts.gitlab.io/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>helm repo update
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="2-在-gitlab-代码仓库中找到-url-和-runner-的-token">2. 在 gitlab 代码仓库中找到 url 和 runner 的 token&lt;/h3>
&lt;p>&lt;img src="https://mydream.ink/assets/images/posts/devops/find-url-and-token.png" alt="获取 Gitlab 的 URL 和 runner 的 token">&lt;/p>
&lt;h3 id="3-安装-gitlab-runner">3. 安装 gitlab-runner&lt;/h3>
&lt;p>我们可以通过参数以及配置文件的形式为 helm 添加自定义配置。该 Chart 的可配置项可以查阅官方库&lt;a href="https://gitlab.com/gitlab-org/charts/gitlab-runner/blob/master/values.yaml">对于 &lt;code>values.yaml&lt;/code> 文件的注释&lt;/a>，这里把关键配置提出来说明一下：&lt;/p>
&lt;ul>
&lt;li>&lt;code>gitlabUrl&lt;/code>：gitlab 服务的地址，形如：https://gitlab.xxx.com；&lt;/li>
&lt;li>&lt;code>runnerRegistrationToken&lt;/code>：上一步中得到的 token；&lt;/li>
&lt;li>&lt;code>rbac.create&lt;/code>：我是没有遇到过没有 &lt;code>rbac&lt;/code> 的 kubernetes 集群，所以记得一定填 &lt;code>true&lt;/code>，否则创建出的 gitlab-runner 将无权对集群进行操作；&lt;/li>
&lt;li>&lt;code>rbac.clusterWideAccess&lt;/code>：如果涉及到在不同的 namespace 跑 job，设置为 &lt;code>true&lt;/code>，否则置为 &lt;code>false&lt;/code>（这只能操作同一 namespace）；&lt;/li>
&lt;li>&lt;code>rbac.serviceAccountName&lt;/code>：如果不设置默认使用 default，如果 sa 专用则建议另起一个名字，以避免 default 权限过大，其它用 default 的 pod 滥用；&lt;/li>
&lt;li>&lt;code>runners.image&lt;/code>：默认镜像，在 gitlab-ci.yml 中的 job 未配置 &lt;code>image&lt;/code> 时将自动选用；&lt;/li>
&lt;li>&lt;code>runners.privileged&lt;/code>：一般在该 runner 需要跑 &lt;code>docker:dind&lt;/code> 镜像时使用；&lt;/li>
&lt;li>&lt;code>runners.namespace&lt;/code>: Job 运行的 namespace；&lt;/li>
&lt;li>&lt;code>runners.imagePullSecrets&lt;/code>：在创建 job 时使用的镜像如果来自于私有仓库则需要配置该字段。注意使用前需要提前创建好对应的 secret；&lt;/li>
&lt;li>&lt;code>runners.cache&lt;/code>：如果要使用 runner 的 cache 功能，需要对此选项进行配置，不同的持久化方式配置不同，有些方式甚至需要对 chart 进行改造。&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>注：该 Chart 的多 runner 注册功能受限，对 kubernetes 的高级功能配置支持也有限，后期我将对这个 Chart 进行改造，使其支持。&lt;/p>
&lt;/blockquote>
&lt;h2 id="浅析-gitlab-ciyml-相关配置">浅析 &lt;code>.gitlab-ci.yml&lt;/code> 相关配置&lt;/h2>
&lt;p>有关 &lt;code>.gitlab-ci.yml&lt;/code> 更详细的配置参照&lt;a href="https://docs.gitlab.com/ee/ci/yaml/README.html">官方文档&lt;/a>，在此仅挑部分有特点的东西记录一下。&lt;/p>
&lt;ol>
&lt;li>image 将确定 job 运行的环境，script 将在该环境中运行；&lt;/li>
&lt;li>service 是环境的依赖，如&lt;code>docker:dind&lt;/code> 一般以这种方式注入，具体在 kubernetes 集群中会以 sidecar 的形式与主环境放在一个 pod 中，所以如果 service 提供的是 socket 服务，在主环境中使用 localhost 即可访问；&lt;/li>
&lt;li>注意 only/except 的&lt;a href="https://docs.gitlab.com/ee/ci/yaml/README.html#onlyexcept-advanced">高级用法&lt;/a>，可以服务于多种场景；&lt;/li>
&lt;li>使用 &lt;a href="https://docs.gitlab.com/ee/ci/yaml/README.html#rules">rules&lt;/a> 对 job 进行合理控制；&lt;/li>
&lt;li>&lt;a href="https://docs.gitlab.com/ee/ci/yaml/README.html#environment">environment&lt;/a> 跟持续部署相关，主要用于前端项目；&lt;/li>
&lt;li>&lt;a href="https://docs.gitlab.com/ee/ci/yaml/README.html#cache">cache&lt;/a> 用于在多个 job 间缓存数据；&lt;/li>
&lt;li>&lt;a href="https://docs.gitlab.com/ee/ci/yaml/README.html#artifacts">artifacts&lt;/a> 将对指定文件（一般是编译产物）进行打包，并上传至 gitlab，供下载使用，这也会在界面进行展示，配合 &lt;a href="https://docs.gitlab.com/ee/ci/yaml/README.html#dependencies">dependencies&lt;/a> 使用，可以在不同 stage 的 job 间进行传递；&lt;/li>
&lt;li>使用 &lt;a href="https://docs.gitlab.com/ee/ci/yaml/README.html#coverage">coverage&lt;/a> 抓取测试覆盖率&lt;/li>
&lt;/ol>
&lt;h2 id="配置-gitlab-ciyml">配置 &lt;code>.gitlab-ci.yml&lt;/code>&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">stages&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">build&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">.build-common&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#75715e">&amp;amp;build-common&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">image&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#ae81ff">docker:latest&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">variables&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">DOCKER_HOST&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#ae81ff">tcp://localhost:2375&lt;/span> &lt;span style="color:#75715e"># kubernetes 集群中使用 localhost 访问&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">DOCKER_DRIVER&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#ae81ff">overlay2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">services&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#f92672">name&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#ae81ff">docker:18-dind&lt;/span> &lt;span style="color:#75715e"># 匹配环境中 docker 的版本&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">command&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;--registry-mirror=https://mirror.ccs.tencentyun.com&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#75715e"># 这是我找到的在编译镜像时，配置镜像加速器的最好办法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">before_script&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">docker login -u &amp;#34;$CI_REGISTRY_USER&amp;#34; -p &amp;#34;$CI_REGISTRY_PASSWORD&amp;#34; $CI_REGISTRY&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">build-master&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;&amp;lt;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#75715e">*build-common&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">stage&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#ae81ff">build&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">script&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">docker build -t &amp;#34;$CI_REGISTRY_IMAGE&amp;#34; .&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">docker tag &amp;#34;$CI_REGISTRY_IMAGE&amp;#34; &amp;#34;$CI_REGISTRY/$CI_REGISTRY_IMAGE&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">docker tag &amp;#34;$CI_REGISTRY_IMAGE&amp;#34; &amp;#34;$CI_REGISTRY/$CI_REGISTRY_IMAGE:${CI_COMMIT_SHA:0:9}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">docker push &amp;#34;$CI_REGISTRY/$CI_REGISTRY_IMAGE&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">docker push &amp;#34;$CI_REGISTRY/$CI_REGISTRY_IMAGE:${CI_COMMIT_SHA:0:9}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">only&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">master&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">build&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;lt;&amp;lt;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#75715e">*build-common&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">stage&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#ae81ff">build&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">script&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">docker build -t &amp;#34;$CI_REGISTRY_IMAGE:${CI_COMMIT_SHA:0:9}&amp;#34; .&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">docker tag &amp;#34;$CI_REGISTRY_IMAGE:${CI_COMMIT_SHA:0:9}&amp;#34; &amp;#34;$CI_REGISTRY/$CI_REGISTRY_IMAGE:${CI_COMMIT_SHA:0:9}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">docker push &amp;#34;$CI_REGISTRY/$CI_REGISTRY_IMAGE:${CI_COMMIT_SHA:0:9}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">except&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">master&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item></channel></rss>