你好! 最近,发布了许多很酷的自动化工具,用于构建 Docker 映像和部署到 Kubernetes。 在这方面,我决定尝试一下 GitLab,彻底研究它的功能,当然,还建立了管道。
这项工作的灵感来自于网站
我尝试从头开始构建类似的流程,但完全基于 Gitlab CI 和我习惯用来将应用程序部署到 Kubernetes 的免费工具。 今天我终于要告诉你更多关于他们的事情了。
本文将讨论以下工具:
雨果, 魁北克, iko子, git 密码 и 亚搏体育app CI 随着动态环境的创建。
内容
认识雨果 准备 Dockerfile 认识卡尼科 了解qbec 尝试使用 Gitlab-runner 和 Kubernetes-executor 使用 qbec 部署 Helm 图表 介绍 git-crypt 创建工具箱图像 我们的第一个管道和按标签组装图像 部署自动化 推动掌握时的工件和装配 动态环境 评论应用
1. 认识雨果
作为我们项目的一个例子,我们将尝试创建一个基于 Hugo 的文档发布网站。 Hugo 是一个静态内容生成器。
对于那些不熟悉静态发生器的人,我会告诉你更多关于它们的信息。 与带有数据库和一些 PHP 的传统网站引擎(当用户请求时动态生成页面)不同,静态生成器的设计略有不同。 它们允许您获取源代码,通常是 Markdown 标记和主题模板中的一组文件,然后将它们编译成一个完整完成的网站。
也就是说,您将收到一个目录结构和一组生成的 HTML 文件,您可以简单地将其上传到任何廉价托管并获得一个可用的网站。
您可以在本地安装 Hugo 并尝试一下:
初始化新站点:
hugo new site docs.example.org
同时 git 存储库:
cd docs.example.org
git init
到目前为止,我们的网站是原始的,为了在其上显示某些内容,我们首先需要连接一个主题;主题只是一组模板和生成我们网站的指定规则。
对于我们将使用的主题
我要特别注意的是,我们不需要将主题文件保存在项目存储库中;相反,我们可以简单地使用以下命令连接它 git子模块:
git submodule add https://github.com/matcornic/hugo-theme-learn themes/learn
这样,我们的存储库将只包含与我们的项目直接相关的文件,并且连接的主题将保留为特定存储库的链接以及其中的提交,也就是说,它始终可以从原始源中拉取而不必担心不兼容的更改。
让我们更正一下配置 配置文件:
baseURL = "http://docs.example.org/"
languageCode = "en-us"
title = "My Docs Site"
theme = "learn"
在此阶段您可以运行:
hugo server
并在地址
让我们尝试创建一个封面页 内容/_index.md:
# My docs site
## Welcome to the docs!
You will be very smart :-)
新创建的页面的屏幕截图
要生成站点,只需运行:
hugo
目录内容 上市/ 并将成为您的网站。
是的,顺便说一下,我们立即将其添加到 的.gitignore:
echo /public > .gitignore
不要忘记提交我们的更改:
git add .
git commit -m "New site created"
2. 准备Dockerfile
是时候定义我们的存储库的结构了。 我通常使用类似的东西:
.
├── deploy
│ ├── app1
│ └── app2
└── dockerfiles
├── image1
└── image2
- dockerfiles/ — 包含包含 Dockerfile 的目录以及构建 Docker 映像所需的所有内容。
- 部署/ — 包含用于将我们的应用程序部署到 Kubernetes 的目录
因此,我们将沿着路径创建第一个 Dockerfile dockerfiles/网站/Dockerfile
FROM alpine:3.11 as builder
ARG HUGO_VERSION=0.62.0
RUN wget -O- https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_linux-64bit.tar.gz | tar -xz -C /usr/local/bin
ADD . /src
RUN hugo -s /src
FROM alpine:3.11
RUN apk add --no-cache darkhttpd
COPY --from=builder /src/public /var/www
ENTRYPOINT [ "/usr/bin/darkhttpd" ]
CMD [ "/var/www" ]
如您所见,Dockerfile 包含两个 从,这个机会称为
因此,最终图像将仅包含 暗httpd (轻量级 HTTP 服务器)和 上市/ — 我们静态生成的网站的内容。
不要忘记提交我们的更改:
git add dockerfiles/website
git commit -m "Add Dockerfile for website"
3.认识卡尼科
作为一个 docker 镜像构建者,我决定使用
要构建图像,只需运行容器即可 卡尼科执行人 并将当前构建上下文传递给它;这也可以通过 docker 在本地完成:
docker run -ti --rm
-v $PWD:/workspace
-v ~/.docker/config.json:/kaniko/.docker/config.json:ro
gcr.io/kaniko-project/executor:v0.15.0
--cache
--dockerfile=dockerfiles/website/Dockerfile
--destination=registry.gitlab.com/kvaps/docs.example.org/website:v0.0.1
哪里 registry.gitlab.com/kvaps/docs.example.org/website — 您的 docker 镜像的名称;构建后,它将自动启动到 docker 注册表中。
参数 - 缓存 允许您在 docker 注册表中缓存层;对于给出的示例,它们将保存在 registry.gitlab.com/kvaps/docs.example.org/website/cache,但您可以使用参数指定另一个路径 --缓存存储库.
docker-registry 的截图
4. 了解qbec
当您需要将应用程序部署到具有不同参数的多个集群并希望在 Git 中以声明方式描述它们时,尤其如此。
Qbec 还允许您通过向 Helm 图表传递必要的参数来渲染 Helm 图表,然后以与常规清单相同的方式操作它们,包括您可以对它们应用各种突变,而这反过来又使您无需使用图表博物馆。 也就是说,您可以直接从它们所属的 git 存储和渲染图表。
正如我之前所说,我们将把所有部署存储在一个目录中 部署/:
mkdir deploy
cd deploy
让我们初始化我们的第一个应用程序:
qbec init website
cd website
现在我们的应用程序的结构如下所示:
.
├── components
├── environments
│ ├── base.libsonnet
│ └── default.libsonnet
├── params.libsonnet
└── qbec.yaml
让我们看一下文件 qbec.yaml:
apiVersion: qbec.io/v1alpha1
kind: App
metadata:
name: website
spec:
environments:
default:
defaultNamespace: docs
server: https://kubernetes.example.org:8443
vars: {}
在这里我们主要感兴趣的是 规范环境,qbec 已经为我们创建了一个默认环境,并从我们当前的 kubeconfig 中获取了服务器地址和命名空间。
现在当部署到 默认 环境中,qbec 将始终仅部署到指定的 Kubernetes 集群和指定的命名空间,也就是说,您不再需要在上下文和命名空间之间切换来执行部署。
如有必要,您可以随时更新此文件中的设置。
您的所有环境均在中描述 qbec.yaml,并在文件中 params.libsonnet,其中表示从哪里获取它们的参数。
接下来我们看到两个目录:
- 组件/ — 我们应用程序的所有清单都将存储在这里;它们可以在 jsonnet 和常规 yaml 文件中进行描述
- 环境/ - 在这里我们将描述我们环境的所有变量(参数)。
默认情况下我们有两个文件:
- 环境/base.libsonnet - 它将包含所有环境的通用参数
- 环境/default.libsonnet — 包含环境覆盖的参数 默认
让我们打开 环境/base.libsonnet 并为我们的第一个组件添加参数:
{
components: {
website: {
name: 'example-docs',
image: 'registry.gitlab.com/kvaps/docs.example.org/website:v0.0.1',
replicas: 1,
containerPort: 80,
servicePort: 80,
nodeSelector: {},
tolerations: [],
ingressClass: 'nginx',
domain: 'docs.example.org',
},
},
}
我们还创建我们的第一个组件 组件/website.jsonnet:
local env = {
name: std.extVar('qbec.io/env'),
namespace: std.extVar('qbec.io/defaultNs'),
};
local p = import '../params.libsonnet';
local params = p.components.website;
[
{
apiVersion: 'apps/v1',
kind: 'Deployment',
metadata: {
labels: { app: params.name },
name: params.name,
},
spec: {
replicas: params.replicas,
selector: {
matchLabels: {
app: params.name,
},
},
template: {
metadata: {
labels: { app: params.name },
},
spec: {
containers: [
{
name: 'darkhttpd',
image: params.image,
ports: [
{
containerPort: params.containerPort,
},
],
},
],
nodeSelector: params.nodeSelector,
tolerations: params.tolerations,
imagePullSecrets: [{ name: 'regsecret' }],
},
},
},
},
{
apiVersion: 'v1',
kind: 'Service',
metadata: {
labels: { app: params.name },
name: params.name,
},
spec: {
selector: {
app: params.name,
},
ports: [
{
port: params.servicePort,
targetPort: params.containerPort,
},
],
},
},
{
apiVersion: 'extensions/v1beta1',
kind: 'Ingress',
metadata: {
annotations: {
'kubernetes.io/ingress.class': params.ingressClass,
},
labels: { app: params.name },
name: params.name,
},
spec: {
rules: [
{
host: params.domain,
http: {
paths: [
{
backend: {
serviceName: params.name,
servicePort: params.servicePort,
},
},
],
},
},
],
},
},
]
在此文件中,我们同时描述了三个 Kubernetes 实体,它们是: 部署, 服务 и 入口。 如果我们愿意,我们可以将它们放入不同的组件中,但在现阶段,一个对我们来说就足够了。
句法 jsonnet 与常规 json 非常相似,原则上,常规 json 已经是有效的 jsonnet,所以首先您可能会更容易使用在线服务,例如 yaml2json 将您常用的 yaml 转换为 json,或者,如果您的组件不包含任何变量,则可以以常规 yaml 的形式描述它们。
使用时 jsonnet 我强烈建议为您的编辑器安装一个插件
例如,有一个 vim 的插件 vim-jsonnet,打开语法高亮并自动执行 jsonnet fmt 每次保存时(需要安装 jsonnet)。
一切准备就绪,现在我们可以开始部署了:
要查看我们得到了什么,让我们运行:
qbec show default
在输出中,您将看到将应用于默认集群的渲染 yaml 清单。
太好了,现在申请:
qbec apply default
在输出中,您将始终看到集群中将执行的操作,qbec 会要求您输入同意更改 y 您将能够确认您的意图。
我们的应用程序已准备就绪并已部署!
如果您进行更改,您始终可以执行以下操作:
qbec diff default
查看这些更改将如何影响当前部署
不要忘记提交我们的更改:
cd ../..
git add deploy/website
git commit -m "Add deploy for website"
5. 尝试使用 Kubernetes-executor 来使用 Gitlab-runner
直到最近我只使用常规 gitlab-runner 在带有 shell 或 docker-executor 的预先准备好的机器(LXC 容器)上。 最初,我们在 gitlab 中全局定义了几个这样的运行程序。 他们收集了所有项目的 docker 镜像。
但实践表明,这种选择无论是从实用性还是安全性来看都不是最理想的。 为每个项目甚至每个环境部署单独的运行程序会更好,在意识形态上也更正确。
幸运的是,这根本不是问题,因为现在我们将部署 gitlab-runner 直接作为我们 Kubernetes 项目的一部分。
Gitlab 提供了一个现成的 Helm Chart,用于将 gitlab-runner 部署到 Kubernetes。 所以你需要做的就是找出 注册令牌 对于我们的项目 设置 -> CI / CD -> 跑步者 并将其传递给掌舵:
helm repo add gitlab https://charts.gitlab.io
helm install gitlab-runner
--set gitlabUrl=https://gitlab.com
--set runnerRegistrationToken=yga8y-jdCusVDn_t4Wxc
--set rbac.create=true
gitlab/gitlab-runner
在哪里:
https://gitlab.com — 您的 Gitlab 服务器的地址。- yga8y-jdCusVDn_t4Wxc — 您的项目的注册令牌。
- rbac.create=true — 为运行者提供必要的权限,以便能够使用 kubernetes-executor 创建 pod 来执行我们的任务。
如果一切都正确完成,您应该会在 部分中看到已注册的跑步者 跑人,在您的项目设置中。
添加的跑步者的屏幕截图
真有这么简单吗? - 是的,就是这么简单! 不再需要手动注册跑步者的麻烦,从现在开始,跑步者将自动创建和销毁。
6. 使用 QBEC 部署 Helm 图表
既然我们决定考虑 gitlab-runner 作为我们项目的一部分,是时候在我们的 Git 存储库中描述它了。
我们可以将其描述为一个单独的组件 官网,但未来我们计划部署不同的副本 官网 很多时候,不像 gitlab-runner,每个 Kubernetes 集群仅部署一次。 因此,让我们为其初始化一个单独的应用程序:
cd deploy
qbec init gitlab-runner
cd gitlab-runner
这次我们不会手动描述 Kubernetes 实体,而是采用现成的 Helm 图表。 qbec 的优点之一是能够直接从 Git 存储库渲染 Helm 图表。
让我们使用 git 子模块连接它:
git submodule add https://gitlab.com/gitlab-org/charts/gitlab-runner vendor/gitlab-runner
现在目录 供应商/gitlab-runner 我们有一个带有 gitlab-runner 图表的存储库。
以类似的方式,您可以连接其他存储库,例如带有官方图表的整个存储库
https://github.com/helm/charts
我们来描述一下这个组件 组件/gitlab-runner.jsonnet:
local env = {
name: std.extVar('qbec.io/env'),
namespace: std.extVar('qbec.io/defaultNs'),
};
local p = import '../params.libsonnet';
local params = p.components.gitlabRunner;
std.native('expandHelmTemplate')(
'../vendor/gitlab-runner',
params.values,
{
nameTemplate: params.name,
namespace: env.namespace,
thisFile: std.thisFile,
verbose: true,
}
)
第一个参数 展开Helm模板 我们将路径传递给图表,然后 参数值,我们从环境参数中获取,然后得到对象
- 名称模板 — 发布名称
- 命名空间 — 命名空间转移到 helm
- 这个文件 — 传递当前文件路径的必需参数
- 详细 - 显示命令 舵模板 渲染图表时包含所有参数
现在让我们描述一下我们组件的参数 环境/base.libsonnet:
local secrets = import '../secrets/base.libsonnet';
{
components: {
gitlabRunner: {
name: 'gitlab-runner',
values: {
gitlabUrl: 'https://gitlab.com/',
rbac: {
create: true,
},
runnerRegistrationToken: secrets.runnerRegistrationToken,
},
},
},
}
注意 跑步者注册令牌 我们从外部文件中获取 秘密/base.libsonnet,让我们创建它:
{
runnerRegistrationToken: 'yga8y-jdCusVDn_t4Wxc',
}
让我们检查一下是否一切正常:
qbec show default
如果一切正常,那么我们可以通过 Helm 删除之前部署的版本:
helm uninstall gitlab-runner
并以相同的方式部署它,但通过 qbec:
qbec apply default
7.git-crypt简介
目前,我们的 gitlab-runner 目录结构如下所示:
.
├── components
│ ├── gitlab-runner.jsonnet
├── environments
│ ├── base.libsonnet
│ └── default.libsonnet
├── params.libsonnet
├── qbec.yaml
├── secrets
│ └── base.libsonnet
└── vendor
└── gitlab-runner (submodule)
但是在 Git 中存储秘密并不安全,不是吗?所以我们需要对它们进行正确的加密。
通常,为了一个变量,这并不总是有意义的。 您可以将秘密转移到 魁北克 并通过 CI 系统的环境变量。
但值得注意的是,还有更复杂的项目可以包含更多秘密;通过环境变量将它们全部转移将非常困难。而且,在这种情况下,我将无法告诉您这样一个出色的工具 git 密码.
git 密码 它还很方便,因为它允许您保存整个秘密历史记录,以及比较、合并和解决冲突,就像我们在 Git 中习惯做的那样。
安装后第一件事 git 密码 我们需要为我们的存储库生成密钥:
git crypt init
如果您有 PGP 密钥,那么您可以立即将自己添加为该项目的合作者:
git-crypt add-gpg-user [email protected]
这样,您始终可以使用您的私钥解密此存储库。
如果您没有 PGP 密钥并且不希望有它,那么您可以采用其他方法并导出项目密钥:
git crypt export-key /path/to/keyfile
因此,任何拥有出口的人 密钥文件 将能够解密您的存储库。
是时候建立我们的第一个秘密了。
让我提醒您,我们仍在目录中 部署/gitlab-runner/,我们有一个目录 秘密/,让我们加密其中的所有文件,为此我们将创建一个文件 秘密/.gitattributes 包含以下内容:
* filter=git-crypt diff=git-crypt
.gitattributes !filter !diff
从内容可以看出,所有文件都被屏蔽了 * 将被驱动通过 git 密码,除了大多数 .git 属性
我们可以通过运行来检查这一点:
git crypt status -e
输出将是存储库中启用加密的所有文件的列表
就这样,现在我们可以安全地提交更改了:
cd ../..
git add .
git commit -m "Add deploy for gitlab-runner"
要阻止存储库,只需运行:
git crypt lock
所有加密的文件都会立即变成二进制文件,无法读取它们。
要解密存储库,请运行:
git crypt unlock
8. 创建工具箱镜像
工具箱映像是包含我们将用于部署项目的所有工具的映像。 Gitlab 运行程序将使用它将来执行典型的部署任务。
这里一切都很简单,让我们创建一个新的 dockerfiles/工具箱/Dockerfile 包含以下内容:
FROM alpine:3.11
RUN apk add --no-cache git git-crypt
RUN QBEC_VER=0.10.3
&& wget -O- https://github.com/splunk/qbec/releases/download/v${QBEC_VER}/qbec-linux-amd64.tar.gz
| tar -C /tmp -xzf -
&& mv /tmp/qbec /tmp/jsonnet-qbec /usr/local/bin/
RUN KUBECTL_VER=1.17.0
&& wget -O /usr/local/bin/kubectl
https://storage.googleapis.com/kubernetes-release/release/v${KUBECTL_VER}/bin/linux/amd64/kubectl
&& chmod +x /usr/local/bin/kubectl
RUN HELM_VER=3.0.2
&& wget -O- https://get.helm.sh/helm-v${HELM_VER}-linux-amd64.tar.gz
| tar -C /tmp -zxf -
&& mv /tmp/linux-amd64/helm /usr/local/bin/helm
正如您所看到的,在此图像中,我们安装了用于部署应用程序的所有实用程序。 我们这里不需要它,除非 Kubectl,但您可能想在管道设置阶段使用它。
此外,为了能够与 Kubernetes 通信并部署到它,我们需要为 gitlab-runner 生成的 pod 配置角色。
为此,我们使用 gitlab-runner 进入目录:
cd deploy/gitlab-runner
并添加一个新组件 组件/rbac.jsonnet:
local env = {
name: std.extVar('qbec.io/env'),
namespace: std.extVar('qbec.io/defaultNs'),
};
local p = import '../params.libsonnet';
local params = p.components.rbac;
[
{
apiVersion: 'v1',
kind: 'ServiceAccount',
metadata: {
labels: {
app: params.name,
},
name: params.name,
},
},
{
apiVersion: 'rbac.authorization.k8s.io/v1',
kind: 'Role',
metadata: {
labels: {
app: params.name,
},
name: params.name,
},
rules: [
{
apiGroups: [
'*',
],
resources: [
'*',
],
verbs: [
'*',
],
},
],
},
{
apiVersion: 'rbac.authorization.k8s.io/v1',
kind: 'RoleBinding',
metadata: {
labels: {
app: params.name,
},
name: params.name,
},
roleRef: {
apiGroup: 'rbac.authorization.k8s.io',
kind: 'Role',
name: params.name,
},
subjects: [
{
kind: 'ServiceAccount',
name: params.name,
namespace: env.namespace,
},
],
},
]
我们还将在中描述新参数 环境/base.libsonnet,现在看起来像这样:
local secrets = import '../secrets/base.libsonnet';
{
components: {
gitlabRunner: {
name: 'gitlab-runner',
values: {
gitlabUrl: 'https://gitlab.com/',
rbac: {
create: true,
},
runnerRegistrationToken: secrets.runnerRegistrationToken,
runners: {
serviceAccountName: $.components.rbac.name,
image: 'registry.gitlab.com/kvaps/docs.example.org/toolbox:v0.0.1',
},
},
},
rbac: {
name: 'gitlab-runner-deploy',
},
},
}
注意 $.components.rbac.name 指的是 姓名 对于组件 RBAC
让我们检查一下发生了什么变化:
qbec diff default
并将我们的更改应用到 Kubernetes:
qbec apply default
另外,不要忘记将我们的更改提交到 git:
cd ../..
git add dockerfiles/toolbox
git commit -m "Add Dockerfile for toolbox"
git add deploy/gitlab-runner
git commit -m "Configure gitlab-runner to use toolbox"
9. 我们的第一个管道和按标签组装图像
我们将在项目的根目录创建 .gitlab-ci.yml 包含以下内容:
.build_docker_image:
stage: build
image:
name: gcr.io/kaniko-project/executor:debug-v0.15.0
entrypoint: [""]
before_script:
- echo "{"auths":{"$CI_REGISTRY":{"username":"$CI_REGISTRY_USER","password":"$CI_REGISTRY_PASSWORD"}}}" > /kaniko/.docker/config.json
build_toolbox:
extends: .build_docker_image
script:
- /kaniko/executor --cache --context $CI_PROJECT_DIR/dockerfiles/toolbox --dockerfile $CI_PROJECT_DIR/dockerfiles/toolbox/Dockerfile --destination $CI_REGISTRY_IMAGE/toolbox:$CI_COMMIT_TAG
only:
refs:
- tags
build_website:
extends: .build_docker_image
variables:
GIT_SUBMODULE_STRATEGY: normal
script:
- /kaniko/executor --cache --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dockerfiles/website/Dockerfile --destination $CI_REGISTRY_IMAGE/website:$CI_COMMIT_TAG
only:
refs:
- tags
请注意我们使用 GIT_SUBMODULE_STRATEGY:正常 对于那些需要在执行前显式初始化子模块的作业。
不要忘记提交我们的更改:
git add .gitlab-ci.yml
git commit -m "Automate docker build"
我想我们可以放心地称之为一个版本 v0.0.1 并添加标签:
git tag v0.0.1
每当我们需要发布新版本时,我们都会添加标签。 Docker 镜像中的标签将与 Git 标签绑定。每次带有新标签的推送都会使用该标签初始化镜像的构建。
将执行 git push --标签,让我们看看我们的第一个管道:
第一个管道的屏幕截图
值得注意的是,通过标签组装适合构建 docker 镜像,但不适合将应用程序部署到 Kubernetes。 由于新标签可以分配给旧提交,在这种情况下,为它们初始化管道将导致旧版本的部署。
为了解决这个问题,通常将docker镜像的构建与标签绑定在一起,并将应用程序部署到分支 主,其中收集的图像的版本是硬编码的。 您可以在此处通过简单的恢复来初始化回滚 主- 分支机构。
10. 部署自动化
为了让 Gitlab-runner 解密我们的秘密,我们需要导出存储库密钥并将其添加到我们的 CI 环境变量中:
git crypt export-key /tmp/docs-repo.key
base64 -w0 /tmp/docs-repo.key; echo
我们将把生成的行保存在 Gitlab 中;为此,我们进入项目设置:
设置 -> CI / CD -> 变量
让我们创建一个新变量:
Type
键
值
保护
蒙面
范围
File
GITCRYPT_KEY
<your string>
true
(在培训期间您可以 false
)
true
All environments
添加的变量的屏幕截图
现在让我们更新我们的 .gitlab-ci.yml 添加到它:
.deploy_qbec_app:
stage: deploy
only:
refs:
- master
deploy_gitlab_runner:
extends: .deploy_qbec_app
variables:
GIT_SUBMODULE_STRATEGY: normal
before_script:
- base64 -d "$GITCRYPT_KEY" | git-crypt unlock -
script:
- qbec apply default --root deploy/gitlab-runner --force:k8s-context __incluster__ --wait --yes
deploy_website:
extends: .deploy_qbec_app
script:
- qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes
在这里,我们为 qbec 启用了几个新选项:
- --根一些/应用程序 — 允许您确定特定应用程序的目录
- --force:k8s-context __incluster__ - 这是一个神奇的变量,表示部署将在 gtilab-runner 运行的同一集群中进行。 这是必要的,因为否则 qbec 会尝试在您的 kubeconfig 中找到合适的 Kubernetes 服务器
- - 等待 — 强制 qbec 等待,直到它创建的资源进入就绪状态,然后才以成功的退出代码退出。
- -是的 - 简单地禁用交互式 shell 你确定吗? 部署时。
不要忘记提交我们的更改:
git add .gitlab-ci.yml
git commit -m "Automate deploy"
之后 git推 我们将看到我们的应用程序是如何部署的:
第二条管道的截图
11. 推到master时的工件和装配
通常,上述步骤足以构建和交付几乎任何微服务,但我们不想每次需要更新站点时都添加标签。 因此,我们将采取更动态的路线,在 master 分支中设置摘要部署。
这个想法很简单:现在我们的形象 官网 每次你推入时都会重建 主,然后自动部署到Kubernetes。
让我们更新这两个作业 .gitlab-ci.yml:
build_website:
extends: .build_docker_image
variables:
GIT_SUBMODULE_STRATEGY: normal
script:
- mkdir -p $CI_PROJECT_DIR/artifacts
- /kaniko/executor --cache --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dockerfiles/website/Dockerfile --destination $CI_REGISTRY_IMAGE/website:$CI_COMMIT_REF_NAME --digest-file $CI_PROJECT_DIR/artifacts/website.digest
artifacts:
paths:
- artifacts/
only:
refs:
- master
- tags
deploy_website:
extends: .deploy_qbec_app
script:
- DIGEST="$(cat artifacts/website.digest)"
- qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST"
请注意我们添加了一个线程 主 к 裁判 为了工作 建立网站 我们现在使用 $CI_COMMIT_REF_NAME 而不是 $CI_COMMIT_TAG,也就是说,我们摆脱了 Git 中的标签,现在我们将推送一个带有初始化管道的提交分支名称的镜像。 值得注意的是,这也适用于标签,这将允许我们在 docker-registry 中保存具有特定版本的站点的快照。
当新版本站点的 docker 标签名称可以不变时,我们仍然必须向 Kubernetes 描述更改,否则它根本不会从新镜像重新部署应用程序,因为它不会注意到部署清单。
选项 —vm:ext-str 摘要=”$DIGEST” for qbec - 允许您将外部变量传递给 jsonnet。 我们希望随着应用程序的每个版本将其重新部署到集群中。 我们不能再使用标签名称,它现在是不可更改的,因为我们需要绑定到图像的特定版本并在其更改时触发部署。
在这里,我们将受益于 Kaniko 将摘要图像保存到文件的能力(选项 --摘要文件)
然后我们将传输这个文件并在部署时读取它。
让我们更新我们的参数 部署/网站/环境/base.libsonnet 现在看起来像这样:
{
components: {
website: {
name: 'example-docs',
image: 'registry.gitlab.com/kvaps/docs.example.org/website@' + std.extVar('digest'),
replicas: 1,
containerPort: 80,
servicePort: 80,
nodeSelector: {},
tolerations: [],
ingressClass: 'nginx',
domain: 'docs.example.org',
},
},
}
完成,现在任何提交 主 初始化 docker 镜像的构建 官网,然后部署到Kubernetes。
不要忘记提交我们的更改:
git add .
git commit -m "Configure dynamic build"
我们稍后会检查 git推 我们应该看到这样的东西:
master 管道的屏幕截图
原则上,我们不需要在每次推送时重新部署 gitlab-runner,当然,除非它的配置没有任何变化,让我们修复它 .gitlab-ci.yml:
deploy_gitlab_runner:
extends: .deploy_qbec_app
variables:
GIT_SUBMODULE_STRATEGY: normal
before_script:
- base64 -d "$GITCRYPT_KEY" | git-crypt unlock -
script:
- qbec apply default --root deploy/gitlab-runner --force:k8s-context __incluster__ --wait --yes
only:
changes:
- deploy/gitlab-runner/**/*
变化 将允许您监视变化 部署/gitlab-runner/ 并且只有在有任何情况时才会触发我们的工作
不要忘记提交我们的更改:
git add .gitlab-ci.yml
git commit -m "Reduce gitlab-runner deploy"
git推,这样更好:
更新后的管道的屏幕截图
12. 动态环境
是时候通过动态环境使我们的管道多样化了。
首先我们来更新一下作业 建立网站 在我们的 .gitlab-ci.yml,从中删除块 仅由,这将强制 Gitlab 在对任何分支的任何提交时触发它:
build_website:
extends: .build_docker_image
variables:
GIT_SUBMODULE_STRATEGY: normal
script:
- mkdir -p $CI_PROJECT_DIR/artifacts
- /kaniko/executor --cache --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dockerfiles/website/Dockerfile --destination $CI_REGISTRY_IMAGE/website:$CI_COMMIT_REF_NAME --digest-file $CI_PROJECT_DIR/artifacts/website.digest
artifacts:
paths:
- artifacts/
然后更新作业 部署网站,在那里添加一个块 环境:
deploy_website:
extends: .deploy_qbec_app
environment:
name: prod
url: https://docs.example.org
script:
- DIGEST="$(cat artifacts/website.digest)"
- qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST"
这将允许 Gitlab 将作业与 刺 环境并显示正确的链接。
现在让我们再添加两个作业:
deploy_website:
extends: .deploy_qbec_app
environment:
name: prod
url: https://docs.example.org
script:
- DIGEST="$(cat artifacts/website.digest)"
- qbec apply default --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST"
deploy_review:
extends: .deploy_qbec_app
environment:
name: review/$CI_COMMIT_REF_NAME
url: http://$CI_ENVIRONMENT_SLUG.docs.example.org
on_stop: stop_review
script:
- DIGEST="$(cat artifacts/website.digest)"
- qbec apply review --root deploy/website --force:k8s-context __incluster__ --wait --yes --vm:ext-str digest="$DIGEST" --vm:ext-str subdomain="$CI_ENVIRONMENT_SLUG" --app-tag "$CI_ENVIRONMENT_SLUG"
only:
refs:
- branches
except:
refs:
- master
stop_review:
extends: .deploy_qbec_app
environment:
name: review/$CI_COMMIT_REF_NAME
action: stop
stage: deploy
before_script:
- git clone "$CI_REPOSITORY_URL" master
- cd master
script:
- qbec delete review --root deploy/website --force:k8s-context __incluster__ --yes --vm:ext-str digest="$DIGEST" --vm:ext-str subdomain="$CI_ENVIRONMENT_SLUG" --app-tag "$CI_ENVIRONMENT_SLUG"
variables:
GIT_STRATEGY: none
only:
refs:
- branches
except:
refs:
- master
when: manual
它们将在推送到除 master 之外的任何分支时启动,并将部署站点的预览版本。
我们看到 qbec 的一个新选项: --应用程序标签 — 它允许您标记应用程序的已部署版本,并且仅在该标记内工作;在 Kubernetes 中创建和销毁资源时,qbec 将仅对它们进行操作。
这样我们就不能为每次评审创建单独的环境,而只是重复使用同一个环境。
这里我们也使用 qbec申请审查而不是 qbec 应用默认值 - 这正是我们尝试描述我们的环境差异(审核和默认)的时刻:
添加 检讨 环境在 部署/网站/qbec.yaml
spec:
environments:
review:
defaultNamespace: docs
server: https://kubernetes.example.org:8443
然后我们将在中声明它 部署/网站/params.libsonnet:
local env = std.extVar('qbec.io/env');
local paramsMap = {
_: import './environments/base.libsonnet',
default: import './environments/default.libsonnet',
review: import './environments/review.libsonnet',
};
if std.objectHas(paramsMap, env) then paramsMap[env] else error 'environment ' + env + ' not defined in ' + std.thisFile
并记下它的自定义参数 部署/网站/环境/review.libsonnet:
// this file has the param overrides for the default environment
local base = import './base.libsonnet';
local slug = std.extVar('qbec.io/tag');
local subdomain = std.extVar('subdomain');
base {
components+: {
website+: {
name: 'example-docs-' + slug,
domain: subdomain + '.docs.example.org',
},
},
}
我们也来仔细看看jobu 停止评论,当分支被删除时会触发,这样gitlab就不会尝试检查它是否被使用 GIT_STRATEGY:无,稍后我们克隆 主- 通过它分支和删除评论。
这有点令人困惑,但我还没有找到更漂亮的方法。
另一种选择是将每个评论部署到酒店名称空间,该名称空间始终可以完全拆除。
不要忘记提交我们的更改:
git add .
git commit -m "Enable automatic review"
git推, git checkout -b 测试, git推送原点测试, 查看:
Gitlab 中创建的环境截图
一切正常吗? - 太好了,删除我们的测试分支: git checkout主, git推送原点:测试,我们检查环境删除作业是否正常运行。
这里我想立即澄清,项目中的任何开发人员都可以创建分支,他也可以更改 .gitlab-ci.yml 文件和访问秘密变量。
因此,强烈建议仅允许将它们用于受保护的分支,例如 主,或为每个环境创建一组单独的变量。
13.审查应用程序
为了显示这些按钮,您需要创建一个文件 .gitlab/route-map.yml 并描述其中的所有路径转换;在我们的例子中,它会非常简单:
# Indices
- source: /content/(.+?)_index.(md|html)/
public: '1'
# Pages
- source: /content/(.+?).(md|html)/
public: '1/'
不要忘记提交我们的更改:
git add .gitlab/
git commit -m "Enable review apps"
git推,并检查:
“查看应用程序”按钮的屏幕截图
工作完成了!
项目来源:
- 在亚特实验室上:
https://gitlab.com/kvaps/docs.example.org - 在 GitHub 上:
https://github.com/kvaps/docs.example.org
感谢您的关注,希望您喜欢
来源: habr.com