The author selected the Tech Education Fund to receive a donation as part of the Write for DOnations program.
作者选择了Tech Education Fund作为“ Write for DOnations”计划的一部分来接受捐赠。
介绍 (Introduction)
Having an automated deployment process is a requirement for a scalable and resilient application, and GitOps, or Git-based DevOps, has rapidly become a popular method of organizing CI/CD with a Git repository as a “single source of truth.” Tools like CircleCI integrate with your GitHub repository, allowing you to test and deploy your code automatically every time you make a change to your repository. When this kind of CI/CD is combined with the flexibility of Kubernetes infrastructure, you can build an application that scales easily with changing demand.
具有可伸缩性和弹性的应用程序必须具有自动化的部署过程,而GitOps (或基于Git的DevOps )已Swift成为一种流行的将CI / CD与Git存储库一起组织为“单一事实来源”的方法。 CircleCI之类的工具与GitHub存储库集成,使您每次更改存储库时都可以自动测试和部署代码。 当这种CI / CD与Kubernetes基础架构的灵活性相结合时,您可以构建可随需求变化轻松扩展的应用程序。
In this article you will use CircleCI to deploy a sample application to a DigitalOcean Kubernetes (DOKS) cluster. After reading this tutorial, you’ll be able to apply these same techniques to deploy other CI/CD tools that are buildable as Docker images.
在本文中,您将使用CircleCI将示例应用程序部署到DigitalOcean Kubernetes(DOKS)集群。 阅读本教程后,您将能够应用这些相同的技术来部署其他可构建为Docker映像的CI / CD工具。
先决条件 (Prerequisites)
To follow this tutorial, you’ll need to have:
要遵循本教程,您需要具备以下条件:
A DigitalOcean account, which you can set up by following the Sign up for a DigitalOcean Account documentation.
一个DigitalOcean帐户 ,您可以按照“ 注册DigitalOcean帐户”文档中的说明进行设置。
Docker installed on your workstation, and knowledge of how to build, remove, and run Docker images. You can install Docker on Ubuntu 18.04 by following the tutorial on How To Install and Use Docker on Ubuntu 18.04.
在您的工作站上安装了Docker ,并了解如何构建,删除和运行Docker映像。 您可以按照有关如何在Ubuntu 18.04上安装和使用Docker的教程,在Ubuntu 18.04上安装Docker 。
Knowledge of how Kubernetes works and how to create deployments and services on it. It’s highly recommended to read the Introduction to Kubernetes article.
了解Kubernetes的工作方式以及如何在其上创建部署和服务。 强烈建议阅读Kubernetes简介文章。
The
kubectl
command line interface tool installed on the computer from which you will control your cluster.安装在将用来控制集群的计算机上的
kubectl
命令行界面工具。An account on Docker Hub to be used to store your sample application image.
Docker Hub上的一个帐户,用于存储您的示例应用程序映像。
A GitHub account and knowledge of Git basics. You can follow the tutorial series Introduction to Git: Installation, Usage, and Branches and How To Create a Pull Request on GitHub to build this knowledge.
GitHub帐户和有关Git基础知识。 您可以按照教程系列Git简介:安装,用法和分支以及如何在GitHub上创建拉取请求来构建此知识。
For this tutorial, you will use Kubernetes version 1.13.5
and kubectl
version 1.10.7
.
在本教程中,您将使用Kubernetes版本1.13.5
和kubectl
版本1.10.7
。
第1步-创建DigitalOcean Kubernetes集群 (Step 1 — Creating Your DigitalOcean Kubernetes Cluster)
Note: You can skip this section if you already have a running DigitalOcean Kubernetes cluster.
注意:如果您已经有运行中的DigitalOcean Kubernetes集群,则可以跳过本节。
In this first step, you will create the DigitalOcean Kubernetes (DOKS) cluster from which you will deploy your sample application. The kubectl
commands executed from your local machine will change or retrieve information directly from the Kubernetes cluster.
在第一步中,您将创建DigitalOcean Kubernetes(DOKS)集群,从该集群将部署示例应用程序。 从本地计算机执行的kubectl
命令将直接从Kubernetes集群更改或检索信息。
Go to the Kubernetes page on your DigitalOcean account.
转到您的DigitalOcean帐户上的Kubernetes页面 。
Click Create a Kubernetes cluster, or click the green Create button at the top right of the page and select Clusters from the dropdown menu.
单击创建Kubernetes集群 ,或单击页面右上方的绿色创建按钮,然后从下拉菜单中选择集群 。
The next page is where you are going to specify the details of your cluster. On Select a Kubernetes version pick version 1.13.5-do.0. If this one is not available, choose a higher one.
下一页将在其中指定群集的详细信息。 在选择Kubernetes版本上,选择version 1.13.5-do.0 。 如果此选项不可用,请选择较高的一个。
For Choose a datacenter region, choose the region closest to you. This tutorial will use San Francisco - 2.
对于“选择数据中心区域” ,选择离您最近的区域。 本教程将使用San Francisco-2 。
You then have the option to build your Node pool(s). On Kubernetes, a node is a worker machine, which contains the services necessary to run pods. On DigitalOcean, each node is a Droplet. Your node pool will consist of a single Standard node. Select the 2GB/1vCPU configuration and change to 1 Node on the number of nodes.
然后,您可以选择构建节点池 。 在Kubernetes上,节点是工作机,其中包含运行Pod所需的服务。 在DigitalOcean上,每个节点都是一个Droplet。 您的节点池将包含一个Standard节点 。 选择2GB / 1vCPU配置,然后将节点数更改为1 Node 。
You can add extra tags if you want; this can be useful if you plan to use DigitalOcean API or just to better organize your node pools.
您可以根据需要添加其他标签; 如果您打算使用DigitalOcean API或只是为了更好地组织节点池,这将很有用。
On Choose a name, for this tutorial, use kubernetes-deployment-tutorial
. This will make it easier to follow throughout while reading the next sections. Finally, click the green Create Cluster button to create your cluster.
在本教程的“选择名称”上 ,使用kubernetes-deployment-tutorial
。 这将使在阅读下一部分的过程中更容易遵循。 最后,单击绿色的“ 创建集群”按钮来创建集群。
After cluster creation, there will be a button on the UI to download a configuration file called Download Config File. This is the file you will be using to authenticate the kubectl
commands you are going to run against your cluster. Download it to your kubectl
machine.
创建集群后,UI上将存在一个按钮,用于下载名为Download Config File的配置文件 。 这是用于对集群运行的kubectl
命令进行身份验证的文件。 将其下载到您的kubectl
机器。
The default way to use that file is to always pass the --kubeconfig
flag and the path to it on all commands you run with kubectl
. For example, if you downloaded the config file to Desktop
, you would run the kubectl get pods
command like this:
使用该文件的默认方法是将始终通过--kubeconfig
标志和它的路径上你运行的所有命令kubectl
。 例如,如果您将配置文件下载到Desktop
,则可以运行kubectl get pods
命令,如下所示:
- kubectl --kubeconfig ~/Desktop/kubernetes-deployment-tutorial-kubeconfig.yaml get pods kubectl --kubeconfig〜/ Desktop / kubernetes-deployment-tutorial-kubeconfig.yaml获取容器
This would yield the following output:
这将产生以下输出:
Output
No resources found.
This means you accessed your cluster. The No resources found.
message is correct, since you don’t have any pods on your cluster.
这意味着您访问了集群。 No resources found.
该消息是正确的,因为您的集群上没有任何吊舱。
If you are not maintaining any other Kubernetes clusters you can copy the kubeconfig file to a folder on your home directory called .kube
. Create that directory in case it does not exist:
如果您不维护任何其他Kubernetes集群,则可以将kubeconfig文件复制到主目录中名为.kube
的文件夹中。 如果该目录不存在,请创建该目录:
- mkdir -p ~/.kube mkdir -p〜/ .kube
Then copy the config file into the newly created .kube
directory and rename it config
:
然后将配置文件复制到新创建的.kube
目录中,并将其重命名为config
:
cp current_kubernetes-deployment-tutorial-kubeconfig.yaml_file_path ~/.kube/config
cp current_kubernetes-deployment-tutorial-kubeconfig.yaml_file_path〜 / .kube / config
The config file should now have the path ~/.kube/config
. This is the file that kubectl
reads by default when running any command, so there is no need to pass --kubeconfig
anymore. Run the following:
现在,配置文件应该具有~/.kube/config
路径。 这是运行任何命令时kubectl
默认读取的文件,因此不再需要传递--kubeconfig
。 运行以下命令:
- kubectl get pods kubectl得到豆荚
You will receive the following output:
您将收到以下输出:
Output
No resources found.
Now access the cluster with the following:
现在,使用以下命令访问集群:
- kubectl get nodes kubectl获取节点
You will receive the list of nodes on your cluster. The output will be similar to this:
您将收到群集上的节点列表。 输出将类似于以下内容:
Output
NAME STATUS ROLES AGE VERSION
kubernetes-deployment-tutorial-1-7pto Ready <none> 1h v1.13.5
In this tutorial you are going to use the default
namespace for all kubectl
commands and manifest files, which are files that define the workload and operating parameters of work in Kubernetes. Namespaces are like virtual clusters inside your single physical cluster. You can change to any other namespace you want; just make sure to always pass it using the --namespace
flag to kubectl
, and/or specifying it on the Kubernetes manifests metadata field. They are a great way to organize the deployments of your team and their running environments; read more about them in the official Kubernetes overview on Namespaces.
在本教程中,您将对所有kubectl
命令和清单文件使用default
命名空间,这些文件和文件定义了Kubernetes中工作的工作量和工作参数。 命名空间就像单个物理群集中的虚拟群集。 您可以更改为所需的任何其他名称空间。 只要确保始终使用--namespace
标志将其传递给kubectl
和/或在Kubernetes清单元数据字段中指定它即可。 它们是组织团队及其运行环境的好方法。 在正式的Kubernetes命名空间概述中阅读有关它们的更多信息。
By finishing this step you are now able to run kubectl
against your cluster. In the next step, you will create the local Git repository you are going to use to house your sample application.
通过完成此步骤,您现在可以对集群运行kubectl
。 在下一步中,您将创建用于存储示例应用程序的本地Git存储库。
第2步-创建本地Git存储库 (Step 2 — Creating the Local Git Repository)
You are now going to structure your sample deployment in a local Git repository. You will also create some Kubernetes manifests that will be global to all deployments you are going to do on your cluster.
现在,您将在本地Git存储库中构建示例部署。 您还将创建一些Kubernetes清单,这些清单对于将在集群上进行的所有部署都是全局的。
Note: This tutorial has been tested on Ubuntu 18.04, and the individual commands are styled to match this OS. However, most of the commands here can be applied to other Linux distributions with little to no change needed, and commands like kubectl
are platform-agnostic.
注意:本教程已经在Ubuntu 18.04上进行了测试,并且各个命令的样式都与该OS相匹配。 但是,此处的大多数命令几乎无需更改即可应用于其他Linux发行版,并且像kubectl
这样的命令与平台无关。
First, create a new Git repository locally that you will push to GitHub later on. Create an empty folder called do-sample-app
in your home directory and cd
into it:
首先,在本地创建一个新的Git存储库,稍后将其推送到GitHub。 在您的主目录中创建一个名为do-sample-app
的空文件夹,并将其插入cd
:
- mkdir ~/do-sample-app mkdir〜/ do-sample-app
- cd ~/do-sample-app cd〜/ do-sample-app
Now create a new Git repository in this folder with the following command:
现在,使用以下命令在此文件夹中创建一个新的Git存储库:
- git init . git init。
Inside this repository, create an empty folder called kube
:
在此存储库内,创建一个名为kube
的空文件夹:
- mkdir ~/do-sample-app/kube/ mkdir〜/ do-sample-app / kube /
This will be the location where you are going to store the Kubernetes resources manifests related to the sample application that you will deploy to your cluster.
这将是您存储与要部署到集群的示例应用程序相关的Kubernetes资源清单的位置。
Now, create another folder called kube-general
, but this time outside of the Git repository you just created. Make it inside your home directory:
现在,创建另一个名为kube-general
文件夹,但这一次是在您刚创建的Git存储库之外。 将其放入您的主目录中:
- mkdir ~/kube-general/ mkdir〜/ kube-general /
This folder is outside of your Git repository because it will be used to store manifests that are not specific to a single deployment on your cluster, but common to multiple ones. This will allow you to reuse these general manifests for different deployments.
该文件夹位于您的Git存储库之外,因为它将用于存储清单,这些清单不是特定于群集上的单个部署,而是多个公用的。 这将允许您将这些常规清单用于不同的部署。
With your folders created and the Git repository of your sample application in place, it’s time to arrange the authentication and authorization of your DOKS cluster.
创建文件夹并放置示例应用程序的Git存储库后,就该安排DOKS集群的身份验证和授权了。
第3步-创建服务帐户 (Step 3 — Creating a Service Account)
It’s generally not recommended to use the default admin user to authenticate from other Services into your Kubernetes cluster. If your keys on the external provider got compromised, your whole cluster would become compromised.
通常不建议使用默认的admin用户从其他服务向Kubernetes集群进行身份验证。 如果您在外部提供程序上的密钥受到破坏,则整个集群将受到破坏。
Instead you are going to use a single Service Account with a specific Role, which is all part of the RBAC Kubernetes authorization model.
相反,您将使用具有特定角色的单个服务帐户 ,这是RBAC Kubernetes授权模型的全部 。
This authorization model is based on Roles and Resources. You start by creating a Service Account, which is basically a user on your cluster, then you create a Role, in which you specify what resources it has access to on your cluster. Finally, you create a Role Binding, which is used to make the connection between the Role and the Service Account previously created, granting to the Service Account access to all resources the Role has access to.
此授权模型基于角色和资源 。 首先创建一个服务帐户 (该帐户基本上是群集上的用户),然后创建一个角色,在其中指定它可以在群集上访问的资源。 最后,您将创建一个Role Binding ,用于在Role和先前创建的Service Account之间建立连接,向Service Account授予对该Role有权访问的所有资源的访问权限。
The first Kubernetes resource you are going to create is the Service Account for your CI/CD user, which this tutorial will name cicd
.
您要创建的第一个Kubernetes资源是CI / CD用户的服务帐户,本教程将其命名为cicd
。
Create the file cicd-service-account.yml
inside the ~/kube-general
folder, and open it with your favorite text editor:
在~/kube-general
文件夹中创建文件cicd-service-account.yml
,然后使用您喜欢的文本编辑器将其打开:
- nano ~/kube-general/cicd-service-account.yml 纳米〜/ kube-general / cicd-service-account.yml
Write the following content on it:
在上面写以下内容:
apiVersion: v1
kind: ServiceAccount
metadata:
name: cicd
namespace: default
This is a YAML file; all Kubernetes resources are represented using one. In this case you are saying this resource is from Kubernetes API version v1
(internally kubectl
creates resources by calling Kubernetes HTTP APIs), and it is a ServiceAccount
.
这是一个YAML文件; 所有Kubernetes资源都用一个表示。 在这种情况下,您要说的是该资源来自Kubernetes API版本v1
(内部kubectl
通过调用Kubernetes HTTP API创建资源),并且它是ServiceAccount
。
The metadata
field is used to add more information about this resource. In this case, you are giving this ServiceAccount
the name cicd
, and creating it on the default
namespace.
metadata
字段用于添加有关此资源的更多信息。 在这种情况下,您cicd
此ServiceAccount
命名为cicd
,并在default
名称空间上创建它。
You can now create this Service Account on your cluster by running kubectl apply
, like the following:
现在,您可以通过运行kubectl apply
在群集上创建此服务帐户,如下所示:
- kubectl apply -f ~/kube-general/ kubectl适用-f〜/ kube-general /
You will recieve output similar to the following:
您将收到类似于以下内容的输出:
Output
serviceaccount/cicd created
To make sure your Service Account is working, try to log in to your cluster using it. To do that you first need to obtain their respective access token and store it in an environment variable. Every Service Account has an access token which Kubernetes stores as a Secret.
为了确保您的服务帐户正常运行,请尝试使用它登录到群集。 为此,您首先需要获取它们各自的访问令牌并将其存储在环境变量中。 每个服务帐户都有一个访问令牌,Kubernetes将其存储为Secret 。
You can retrieve this secret using the following command:
您可以使用以下命令检索此机密:
- TOKEN=$(kubectl get secret $(kubectl get secret | grep cicd-token | awk '{print $1}') -o jsonpath='{.data.token}' | base64 --decode) 令牌= $(kubectl取得秘密$(kubectl取得秘密| grep cicd令牌| awk'{print $ 1}')-o jsonpath ='{。data.token}'| base64 --decode)
Some explanation on what this command is doing:
关于此命令的作用的一些解释:
$(kubectl get secret | grep cicd-token | awk '{print $1}')
This is used to retrieve the name of the secret related to our cicd
Service Account. kubectl get secret
returns the list of secrets on the default namespace, then you use grep
to search for the lines related to your cicd
Service Account. Then you return the name, since it is the first thing on the single line returned from the grep
.
这用于检索与我们的cicd
服务帐户相关的机密名称。 kubectl get secret
返回默认名称空间上的秘密列表,然后使用grep
搜索与cicd
服务帐户相关的行。 然后返回名称,因为它是grep
返回的第一行。
kubectl get secret preceding-command -o jsonpath='{.data.token}' | base64 --decode
This will retrieve only the secret for your Service Account token. You then access the token field using jsonpath
, and pass the result to base64 --decode
. This is necessary because the token is stored as a Base64 string. The token itself is a JSON Web Token.
这将仅检索您的服务帐户令牌的机密。 然后,您可以使用jsonpath
访问令牌字段,并将结果传递给base64 --decode
。 这是必需的,因为令牌存储为Base64字符串。 令牌本身是JSON Web令牌 。
You can now try to retrieve your pods with the cicd
Service Account. Run the following command, replacing server-from-kubeconfig-file
with the server URL that can be found after server:
in ~kube/config
. This command will give a specific error that you will learn about later in this tutorial:
现在,您可以尝试使用cicd
服务帐户检索您的cicd
。 运行以下命令,将server-from-kubeconfig-file
替换为server之后可以找到的服务器URL server:
~kube/config
。 此命令将给出特定的错误,您将在本教程的后面部分中学习该错误:
kubectl --insecure-skip-tls-verify --kubeconfig="/dev/null" --server=server-from-kubeconfig-file --token=$TOKEN get pods
kubectl --insecure-skip-tls-verify --kubeconfig =“ / dev / null” --server = 服务器从kubeconfig文件 --token = $ TOKEN获取容器
--insecure-skip-tls-verify
skips the step of verifying the certificate of the server, since you are just testing and do not need to verify this. --kubeconfig="/dev/null"
is to make sure kubectl
does not read your config file and credentials but instead uses the token provided.
--insecure-skip-tls-verify
跳过了验证服务器证书的步骤,因为您只是在测试,不需要验证。 --kubeconfig="/dev/null"
是为了确保kubectl
不会读取您的配置文件和凭据,而是使用提供的令牌。
The output should be similar to this:
输出应类似于以下内容:
Output
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:default:cicd" cannot list resource "pods" in API group "" in the namespace "default"
This is an error, but it shows us that the token worked. The error you received is about your Service Account not having the neccessary authorization to list the resource secrets
, but you were able to access the server itself. If your token had not worked, the error would have been the following one:
这是一个错误,但它向我们显示了令牌已起作用。 您收到的错误是有关您的服务帐户没有必要的权限来列出资源secrets
,但是您可以访问服务器本身。 如果您的令牌无效,则可能是以下错误:
Output
error: You must be logged in to the server (Unauthorized)
Now that the authentication was a success, the next step is to fix the authorization error for the Service Account. You will do this by creating a role with the necessary permissions and binding it to your Service Account.
现在身份验证已成功,下一步是修复服务帐户的授权错误。 为此,您将创建一个具有必要权限的角色并将其绑定到您的服务帐户。
步骤4 —创建角色和角色绑定 (Step 4 — Creating the Role and the Role Binding)
Kubernetes has two ways to define roles: using a Role
or a ClusterRole
resource. The difference between the former and the latter is that the first one applies to a single namespace, while the other is valid for the whole cluster.
Kubernetes有两种定义角色的方法:使用Role
或ClusterRole
资源。 前者和后者的区别在于,第一个适用于单个名称空间,而另一个适用于整个集群。
As you are using a single namespace on this tutorial, you will use a Role
.
在本教程中使用单个名称空间时,将使用Role
。
Create the file ~/kube-general/cicd-role.yml
and open it with your favorite text editor:
创建文件~/kube-general/cicd-role.yml
并使用您喜欢的文本编辑器将其打开:
- nano ~/kube-general/cicd-role.yml 纳米〜/ kube-general / cicd-role.yml
The basic idea is to grant access to do everything related to most Kubernetes resources in the default
namespace. Your Role
would look like this:
基本思想是授予访问权限以执行与default
名称空间中与大多数Kubernetes资源相关的所有操作。 您的Role
将如下所示:
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: cicd
namespace: default
rules:
- apiGroups: ["", "apps", "batch", "extensions"]
resources: ["deployments", "services", "replicasets", "pods", "jobs", "cronjobs"]
verbs: ["*"]
This YAML has some similarities with the one you created previously, but here you are saying this resource is a Role
, and it’s from the Kubernetes API rbac.authorization.k8s.io/v1
. You are naming your role cicd
, and creating it on the same namespace you created your ServiceAccount
, the default
one.
这个YAML与您先前创建的YAML有一些相似之处,但是在这里您是说此资源是一个Role
,它来自Kubernetes API rbac.authorization.k8s.io/v1
。 您正在命名角色cicd
,并在创建ServiceAccount
的default
命名空间的同一命名空间上创建它。
Then you have the rules
field, which is a list of resources this role has access to. In Kubernetes resources are defined based on the API group they belong to, the resource kind itself, and what actions you can do on then, which is represented by a verb. Those verbs are similar to the HTTP ones.
然后,您将拥有rules
字段,该字段是此角色可以访问的资源的列表。 在Kubernetes中,资源是根据它们所属的API组,资源种类本身以及可以对其执行的操作来定义的,它们由动词表示。 这些动词类似于HTTP的动词 。
In our case you are saying that your Role
is allowed to do everything, *
, on the following resources: deployments
, services
, replicasets
, pods
, jobs
, and cronjobs
. This also applies to those resources belonging to the following API groups: ""
(empty string), apps
, batch
, and extensions
. The empty string means the root API group. If you use apiVersion: v1
when creating a resource it means this resource is part of this API group.
在我们的案例中,您是说您的Role
被允许在以下资源上做所有事情*
: deployments
, services
, replicasets
, pods
, jobs
和cronjobs
。 这也适用于属于以下API组的那些资源: ""
(空字符串), apps
, batch
和extensions
。 空字符串表示根API组。 如果在创建资源时使用apiVersion: v1
,则意味着该资源是此API组的一部分。
A Role
by itself does nothing; you must also create a RoleBinding
, which binds a Role
to something, in this case, a ServiceAccount
.
Role
本身不执行任何操作; 您还必须创建RoleBinding
,该Role
将Role
绑定到某些东西(在本例中为ServiceAccount
。
Create the file ~/kube-general/cicd-role-binding.yml
and open it:
创建文件~/kube-general/cicd-role-binding.yml
并打开它:
- nano ~/kube-general/cicd-role-binding.yml 纳米〜/ kube-general / cicd-role-binding.yml
Add the following lines to the file:
将以下行添加到文件中:
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: cicd
namespace: default
subjects:
- kind: ServiceAccount
name: cicd
namespace: default
roleRef:
kind: Role
name: cicd
apiGroup: rbac.authorization.k8s.io
Your RoleBinding
has some specific fields that have not yet been covered in this tutorial. roleRef
is the Role
you want to bind to something; in this case it is the cicd
role you created earlier. subjects
is the list of resources you are binding your role to; in this case it’s a single ServiceAccount
called cicd
.
您的RoleBinding
具有本教程中尚未涵盖的某些特定字段。 roleRef
是您要绑定到某物的Role
; 在这种情况下,这是您之前创建的cicd
角色。 subjects
是您要绑定角色的资源列表; 在这种情况下,这是一个称为cicd
ServiceAccount
。
Note: If you had used a ClusterRole
, you would have to create a ClusterRoleBinding
instead of a RoleBinding
. The file would be almost the same. The only difference would be that it would have no namespace
field inside the metadata
.
注意:如果使用过ClusterRole
,则必须创建ClusterRoleBinding
而不是RoleBinding
。 该文件将几乎相同。 唯一的区别是,它在metadata
内没有namespace
字段。
With those files created you will be able to use kubectl apply
again. Create those new resources on your Kubernetes cluster by running the following command:
创建这些文件后,您将能够再次使用kubectl apply
。 通过运行以下命令在Kubernetes集群上创建这些新资源:
- kubectl apply -f ~/kube-general/ kubectl适用-f〜/ kube-general /
You will receive output similar to the following:
您将收到类似于以下内容的输出:
Output
rolebinding.rbac.authorization.k8s.io/cicd created
role.rbac.authorization.k8s.io/cicd created
serviceaccount/cicd created
Now, try the command you ran previously:
现在,尝试以前运行的命令:
kubectl --insecure-skip-tls-verify --kubeconfig="/dev/null" --server=server-from-kubeconfig-file --token=$TOKEN get pods
kubectl --insecure-skip-tls-verify --kubeconfig =“ / dev / null” --server = 服务器从kubeconfig文件 --token = $ TOKEN获取容器
Since you have no pods, this will yield the following output:
由于没有吊舱,因此将产生以下输出:
Output
No resources found.
In this step, you gave the Service Account you are going to use on CircleCI the necessary authorization to do meaningful actions on your cluster like listing, creating, and updating resources. Now it’s time to create your sample application.
在此步骤中,您为要在CircleCI上使用的服务帐户授予了必要的授权,以对集群执行有意义的操作,例如列出,创建和更新资源。 现在该创建示例应用程序了。
步骤5 —创建示例应用程序 (Step 5 — Creating Your Sample Application)
Note: All commands and files created from now on will start from the folder ~/do-sample-app
you created earlier. This is becase you are now creating files specific to the sample application that you are going to deploy to your cluster.
注意:从现在开始创建的所有命令和文件将从您之前创建的文件夹~/do-sample-app
。 这是在您现在要创建特定于要部署到群集的示例应用程序的文件的情况下。
The Kubernetes Deployment
you are going to create will use the Nginx image as a base, and your application will be a simple static HTML page. This is a great start because it allows you to test if your deployment works by serving a simple HTML directly from Nginx. As you will see later on, you can redirect all traffic coming to a local address:port
to your deployment on your cluster to test if it’s working.
您将要创建的Kubernetes Deployment
将使用Nginx图像作为基础,您的应用程序将是一个简单的静态HTML页面。 这是一个很好的开始,因为它允许您通过直接从Nginx提供简单HTML来测试您的部署是否有效。 稍后将看到,您可以将所有到达本地address:port
流量重定向到群集上的部署,以测试其是否正常运行。
Inside the repository you set up earlier, create a new Dockerfile
file and open it with your text editor of choice:
在您之前设置的存储库中,创建一个新的Dockerfile
文件,然后使用您选择的文本编辑器将其打开:
- nano ~/do-sample-app/Dockerfile 纳米〜/ do-sample-app / Dockerfile
Write the following on it:
在上面写以下内容:
FROM nginx:1.14
COPY index.html /usr/share/nginx/html/index.html
This will tell Docker to build the application container from an nginx
image.
这将告诉Docker从nginx
映像构建应用程序容器。
Now create a new index.html
file and open it:
现在创建一个新的index.html
文件并打开它:
- nano ~/do-sample-app/index.html 纳米〜/ do-sample-app / index.html
Write the following HTML content:
编写以下HTML内容:
<!DOCTYPE html>
<title>DigitalOcean</title>
<body>
Kubernetes Sample Application
</body>
This HTML will display a simple message that will let you know if your application is working.
该HTML将显示一条简单的消息,让您知道您的应用程序是否正在运行。
You can test if the image is correct by building and then running it.
您可以通过构建然后运行它来测试图像是否正确。
First, build the image with the following command, replacing dockerhub-username
with your own Docker Hub username. You must specify your username here so when you push it later on to Docker Hub it will just work:
首先,使用以下命令构建映像,将dockerhub-username
替换为您自己的Docker Hub用户名。 您必须在此处指定您的用户名,以便稍后将其推送到Docker Hub时就可以使用:
docker build ~/do-sample-app/ -t dockerhub-username/do-kubernetes-sample-app
docker build〜 / do-sample-app / -t dockerhub用户名 / do-kubernetes-sample-app
Now run the image. Use the following command, which starts your image and forwards any local traffic on port 8080
to the port 80
inside the image, the port Nginx listens to by default:
现在运行图像。 使用以下命令启动您的映像,并将端口8080
上的所有本地流量转发到映像内的端口80
,默认情况下Nginx侦听端口:
docker run --rm -it -p 8080:80 dockerhub-username/do-kubernetes-sample-app
docker run --rm -it -p 8080:80 dockerhub用户名 / do-kubernetes-sample-app
The command prompt will stop being interactive while the command is running. Instead you will see the Nginx access logs. If you open localhost:8080
on any browser it should show an HTML page with the content of ~/do-sample-app/index.html
. In case you don’t have a browser available, you can open a new terminal window and use the following curl
command to fetch the HTML from the webpage:
运行命令时,命令提示符将停止交互。 相反,您将看到Nginx访问日志。 如果您在任何浏览器上打开localhost:8080
,它将显示一个HTML页面,其内容为~/do-sample-app/index.html
。 如果没有可用的浏览器,则可以打开一个新的终端窗口,并使用以下curl
命令从网页中获取HTML:
- curl localhost:8080 curl本地主机:8080
You will receive the following output:
您将收到以下输出:
Output
<!DOCTYPE html>
<title>DigitalOcean</title>
<body>
Kubernetes Sample Application
</body>
Stop the container (CTRL
+ C
on the terminal where it’s running), and submit this image to your Docker Hub account. To do this, first log in to Docker Hub:
停止容器(运行该终端的CTRL
+ C
),然后将此映像提交到您的Docker Hub帐户。 为此,请首先登录Docker Hub:
- docker login 码头工人登录
Fill in the required information about your Docker Hub account, then push the image with the following command (don’t forget to replace the dockerhub-username
with your own):
填写有关您的Docker Hub帐户的必需信息,然后使用以下命令推送映像(不要忘记用您自己的dockerhub-username
替换):
docker push dockerhub-username/do-kubernetes-sample-app
docker push dockerhub用户名 / do-kubernetes-sample-app
You have now pushed your sample application image to your Docker Hub account. In the next step, you will create a Deployment on your DOKS cluster from this image.
现在,您已将示例应用程序映像推送到Docker Hub帐户。 在下一步中,您将根据该映像在DOKS集群上创建一个Deployment。
步骤6 —创建Kubernetes部署和服务 (Step 6 — Creating the Kubernetes Deployment and Service)
With your Docker image created and working, you will now create a manifest telling Kubernetes how to create a Deployment from it on your cluster.
创建并运行Docker映像后,您现在将创建一个清单,告诉Kubernetes如何在群集上从中创建Deployment 。
Create the YAML deployment file ~/do-sample-app/kube/do-sample-deployment.yml
and open it with your text editor:
创建YAML部署文件~/do-sample-app/kube/do-sample-deployment.yml
并使用文本编辑器将其打开:
- nano ~/do-sample-app/kube/do-sample-deployment.yml 纳米〜/ do-sample-app / kube / do-sample-deployment.yml
Write the following content on the file, making sure to replace dockerhub-username
with your Docker Hub username:
在文件上写以下内容,确保用Docker Hub用户名替换dockerhub-username
username:
apiVersion: apps/v1
kind: Deployment
metadata:
name: do-kubernetes-sample-app
namespace: default
labels:
app: do-kubernetes-sample-app
spec:
replicas: 1
selector:
matchLabels:
app: do-kubernetes-sample-app
template:
metadata:
labels:
app: do-kubernetes-sample-app
spec:
containers:
- name: do-kubernetes-sample-app
image: dockerhub-username/do-kubernetes-sample-app:latest
ports:
- containerPort: 80
name: http
Kubernetes deployments are from the API group apps
, so the apiVersion
of your manifest is set to apps/v1
. On metadata
you added a new field you have not used previously, called metadata.labels
. This is useful to organize your deployments. The field spec
represents the behavior specification of your deployment. A deployment is responsible for managing one or more pods; in this case it’s going to have a single replica by the spec.replicas
field. That is, it’s going to create and manage a single pod.
Kubernetes部署来自API组apps
,因此清单的apiVersion
设置为apps/v1
。 在metadata
,添加了一个以前从未使用过的新字段,称为metadata.labels
。 这对组织部署很有用。 字段spec
表示部署的行为规范。 部署负责管理一个或多个pod。 在这种情况下, spec.replicas
字段将只有一个副本。 也就是说,它将创建和管理单个吊舱。
To manage pods, your deployment must know which pods it’s responsible for. The spec.selector
field is the one that gives it that information. In this case the deployment will be responsible for all pods with tags app=do-kubernetes-sample-app
. The spec.template
field contains the details of the Pod
this deployment will create. Inside the template you also have a spec.template.metadata
field. The labels
inside this field must match the ones used on spec.selector
. spec.template.spec
is the specification of the pod itself. In this case it contains a single container, called do-kubernetes-sample-app
. The image of that container is the image you built previously and pushed to Docker Hub.
要管理Pod,您的部署必须知道它负责哪个Pod。 spec.selector
字段是spec.selector
提供该信息的字段。 在这种情况下,部署将负责所有带有标签app=do-kubernetes-sample-app
吊舱。 spec.template
字段包含此部署将创建的Pod
的详细信息。 在模板内部,您还具有一个spec.template.metadata
字段。 此字段内的labels
必须与spec.selector
使用的labels
匹配。 spec.template.spec
是容器本身的规范。 在这种情况下,它包含一个名为do-kubernetes-sample-app
容器。 该容器的映像是您先前构建并推送到Docker Hub的映像。
This YAML file also tells Kubernetes that this container exposes the port 80
, and gives this port the name http
.
该YAML文件还告诉Kubernetes,此容器公开了端口80
,并将该端口命名为http
。
To access the port exposed by your Deployment
, create a Service. Make a file named ~/do-sample-app/kube/do-sample-service.yml
and open it with your favorite editor:
要访问Deployment
公开的端口,请创建服务。 制作一个名为~/do-sample-app/kube/do-sample-service.yml
,然后使用您喜欢的编辑器将其打开:
- nano ~/do-sample-app/kube/do-sample-service.yml 纳米〜/ do-sample-app / kube / do-sample-service.yml
Next, add the following lines to the file:
接下来,将以下行添加到文件中:
apiVersion: v1
kind: Service
metadata:
name: do-kubernetes-sample-app
namespace: default
labels:
app: do-kubernetes-sample-app
spec:
type: ClusterIP
ports:
- port: 80
targetPort: http
name: http
selector:
app: do-kubernetes-sample-app
This file gives your Service
the same labels used on your deployment. This is not required, but it helps to organize your applications on Kubernetes.
该文件为您的Service
了与部署相同的标签。 这不是必需的,但有助于在Kubernetes上组织应用程序。
The service resource also has a spec
field. The spec.type
field is responsible for the behavior of the service. In this case it’s a ClusterIP
, which means the service is exposed on a cluster-internal IP, and is only reachable from within your cluster. This is the default spec.type
for services. spec.selector
is the label selector criteria that should be used when picking the pods to be exposed by this service. Since your pod has the tag app: do-kubernetes-sample-app
, you used it here. spec.ports
are the ports exposed by the pod’s containers that you want to expose from this service. Your pod has a single container which exposes port 80
, named http
, so you are using it here as targetPort
. The service exposes that port on port 80
too, with the same name, but you could have used a different port/name combination than the one from the container.
服务资源也有一个spec
字段。 spec.type
字段负责服务的行为。 在这种情况下,它是一个ClusterIP
,这意味着该服务公开在群集内部的IP上,并且只能从您的群集内部访问。 这是服务的默认spec.type
。 spec.selector
是选择该服务要暴露的spec.selector
时应使用的标签选择器标准。 由于您的广告连播具有标签app: do-kubernetes-sample-app
,因此您在这里使用了它。 spec.ports
是要从此服务公开的Pod容器公开的端口。 您的pod拥有一个单独的容器,该容器公开了名为http
端口80
,因此您在此处将其用作targetPort
。 该服务也使用相同的名称在端口80
上公开该端口,但是您可以使用与容器中的端口/名称组合不同的端口/名称组合。
With your Service
and Deployment
manifest files created, you can now create those resources on your Kubernetes cluster using kubectl
:
创建Service
和Deployment
清单文件后,您现在可以使用kubectl
在Kubernetes集群上创建这些资源:
- kubectl apply -f ~/do-sample-app/kube/ kubectl应用-f〜/ do-sample-app / kube /
You will receive the following output:
您将收到以下输出:
Output
deployment.apps/do-kubernetes-sample-app created
service/do-kubernetes-sample-app created
Test if this is working by forwarding one port on your machine to the port that the service is exposing inside your Kubernetes cluster. You can do that using kubectl port-forward
:
通过将机器上的一个端口转发到该服务在Kubernetes群集中公开的端口来测试其是否有效。 您可以使用kubectl port-forward
:
- kubectl port-forward $(kubectl get pod --selector="app=do-kubernetes-sample-app" --output jsonpath='{.items[0].metadata.name}') 8080:80 kubectl端口转发$(kubectl get pod --selector =“ app = do-kubernetes-sample-app” --output jsonpath ='{。items [0] .metadata.name}')8080:80
The subshell command $(kubectl get pod --selector="app=do-kubernetes-sample-app" --output jsonpath='{.items[0].metadata.name}')
retrieves the name of the pod matching the tag you used. Otherwise you could have retrieved it from the list of pods by using kubectl get pods
.
子shell命令$(kubectl get pod --selector="app=do-kubernetes-sample-app" --output jsonpath='{.items[0].metadata.name}')
检索与您使用的标签。 否则,您可以使用kubectl get pods
从pod列表中检索到它。
After you run port-forward
, the shell will stop being interactive, and will instead output the requests redirected to your cluster:
在运行port-forward
,shell将停止交互,而将输出重定向到集群的请求:
Output
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
Opening localhost:8080
on any browser should render the same page you saw when you ran the container locally, but it’s now coming from your Kubernetes cluster! As before, you can also use curl
in a new terminal window to check if it’s working:
在任何浏览器上打开localhost:8080
应该呈现与在本地运行容器时看到的页面相同的页面,但是现在它来自您的Kubernetes集群! 和以前一样,您也可以在新的终端窗口中使用curl
来检查它是否正常工作:
- curl localhost:8080 curl本地主机:8080
You will receive the following output:
您将收到以下输出:
Output
<!DOCTYPE html>
<title>DigitalOcean</title>
<body>
Kubernetes Sample Application
</body>
Next, it’s time to push all the files you created to your GitHub repository. To do this you must first create a repository on GitHub called digital-ocean-kubernetes-deploy
.
接下来,是时候将您创建的所有文件推送到GitHub存储库中了。 为此,您必须首先在GitHub上创建一个名为digital-ocean-kubernetes-deploy
的存储库 。
In order to keep this repository simple for demonstration purposes, do not initialize the new repository with a README
, license
, or .gitignore
file when asked on the GitHub UI. You can add these files later on.
为了使此存储库简单易行,以进行演示,在GitHub UI上询问时,请勿使用README
, license
或.gitignore
文件初始化新存储库。 您可以稍后添加这些文件。
With the repository created, point your local repository to the one on GitHub. To do this, press CTRL
+ C
to stop kubectl port-forward
and get the command line back, then run the following commands to add a new remote called origin
:
创建存储库后,将本地存储库指向GitHub上的存储库。 为此,请按CTRL
+ C
停止kubectl port-forward
并返回命令行,然后运行以下命令以添加一个名为origin
的新远程:
- cd ~/do-sample-app/ cd〜/ do-sample-app /
git remote add origin https://github.com/your-github-account-username/digital-ocean-kubernetes-deploy.git
git remote add origin https://github.com/ your-github-account-username /digital-ocean-kubernetes-deploy.git
There should be no output from the preceding command.
前面的命令应该没有输出。
Next, commit all the files you created up to now to the GitHub repository. First, add the files:
接下来,将您到目前为止创建的所有文件提交到GitHub存储库。 首先,添加文件:
- git add --all git添加--all
Next, commit the files to your repository, with a commit message in quotation marks:
接下来,使用引号将提交消息提交到您的存储库中:
- git commit -m "initial commit" git commit -m“初始提交”
This will yield output similar to the following:
这将产生类似于以下内容的输出:
Output
[master (root-commit) db321ad] initial commit
4 files changed, 47 insertions(+)
create mode 100644 Dockerfile
create mode 100644 index.html
create mode 100644 kube/do-sample-deployment.yml
create mode 100644 kube/do-sample-service.yml
Finally, push the files to GitHub:
最后,将文件推送到GitHub:
- git push -u origin master git push -u原始主机
You will be prompted for your username and password. Once you have entered this, you will see output like this:
系统将提示您输入用户名和密码。 输入此内容后,您将看到如下输出:
Output
Counting objects: 7, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (7/7), done.
Writing objects: 100% (7/7), 907 bytes | 0 bytes/s, done.
Total 7 (delta 0), reused 0 (delta 0)
To github.com:your-github-account-username/digital-ocean-kubernetes-deploy.git
* [new branch] master -> master
Branch master set up to track remote branch master from origin.
If you go to your GitHub repository page you will now see all the files there. With your project up on GitHub, you can now set up CircleCI as your CI/CD tool.
如果您转到GitHub存储库页面,现在将在此处看到所有文件。 在GitHub上建立项目后,您现在可以将CircleCI设置为CI / CD工具。
第7步-配置CircleCI (Step 7 — Configuring CircleCI)
For this tutorial, you will use CircleCI to automate deployments of your application whenever the code is updated, so you will need to log in to CircleCI using your GitHub account and set up your repository.
对于本教程,无论代码何时更新,您都将使用CircleCI来自动执行应用程序的部署,因此您将需要使用GitHub帐户登录CircleCI并设置存储库。
First, go to their homepage https://circleci.com
, and press Sign Up.
首先,转到他们的主页https://circleci.com
,然后按注册 。
You are using GitHub, so click the green Sign Up with GitHub button.
您正在使用GitHub,因此请单击绿色的“使用GitHub注册”按钮。
CircleCI will redirect to an authorization page on GitHub. CircleCI needs some permissions on your account to be able to start building your projects. This allows CircleCI to obtain your email, deploy keys and permission to create hooks on your repositories, and add SSH keys to your account. If you need more information on what CircleCI is going to do with your data, check their documentation about GitHub integration.
CircleCI将重定向到GitHub上的授权页面。 CircleCI需要您的帐户具有某些权限才能开始构建您的项目。 这样,CircleCI可以获取您的电子邮件,部署密钥和在存储库上创建钩子的权限以及向您的帐户添加SSH密钥的权限。 如果您需要有关CircleCI将如何处理数据的更多信息,请查看其关于GitHub集成的文档 。
After authorizing CircleCI you will be redirected to their dashboard.
授权CircleCI后,您将被重定向到他们的仪表板。
Next, set up your GitHub repository in CircleCI. Click on Set Up New Projects from the CircleCI Dashboard, or as a shortcut, open the following link changing the highlighted text with your own GitHub username: https://circleci.com/setup-project/gh/your-github-username/digital-ocean-kubernetes-deploy
.
接下来,在CircleCI中设置您的GitHub存储库。 单击从CircleCI仪表板设置新项目 ,或作为快捷方式,打开以下链接,使用您自己的GitHub用户名更改突出显示的文本: https://circleci.com/setup-project/gh/ your-github-username /digital-ocean-kubernetes-deploy
: https://circleci.com/setup-project/gh/ your-github-username /digital-ocean-kubernetes-deploy
。
After that press Start Building. Do not create a config file in your repository just yet, and don’t worry if the first build fails.
之后,按开始构建 。 暂时不要在存储库中创建配置文件,也不必担心第一次构建失败。
Next, specify some environment variables in the CircleCI settings. You can find the settings of the project by clicking on the small button with a cog icon on the top right section of the page then selecting Environment Variables, or you can go directly to the environment variables page by using the following URL (remember to fill in your username): https://circleci.com/gh/your-github-username/digital-ocean-kubernetes-deploy/edit#env-vars
. Press Add Variable to create new environment variables.
接下来,在CircleCI设置中指定一些环境变量。 您可以通过单击页面右上角带有齿轮图标的小按钮,然后选择“ 环境变量”来找到项目的设置,也可以使用以下URL直接进入环境变量页面(请记住填写在您的用户名中): https://circleci.com/gh/ your-github-username /digital-ocean-kubernetes-deploy/edit#env-vars
: https://circleci.com/gh/ your-github-username /digital-ocean-kubernetes-deploy/edit#env-vars
按添加变量以创建新的环境变量。
First, add two environment variables called DOCKERHUB_USERNAME
and DOCKERHUB_PASS
which will be needed later on to push the image to Docker Hub. Set the values to your Docker Hub username and password, respectively.
首先,添加两个名为DOCKERHUB_USERNAME
和DOCKERHUB_PASS
环境变量,稍后需要将其推送到Docker Hub。 将值分别设置为您的Docker Hub用户名和密码。
Then add three more: KUBERNETES_TOKEN
, KUBERNETES_SERVER
, and KUBERNETES_CLUSTER_CERTIFICATE
.
然后再添加三个: KUBERNETES_TOKEN
, KUBERNETES_SERVER
和KUBERNETES_CLUSTER_CERTIFICATE
。
The value of KUBERNETES_TOKEN
will be the value of the local environment variable you used earlier to authenticate on your Kubernetes cluster using your Service Account user. If you have closed the terminal, you can always run the following command to retrieve it again:
KUBERNETES_TOKEN
的值将是您先前使用服务帐户用户在Kubernetes集群上进行身份验证所使用的本地环境变量的值。 如果已关闭终端,则始终可以运行以下命令以再次检索它:
- kubectl get secret $(kubectl get secret | grep cicd-token | awk '{print $1}') -o jsonpath='{.data.token}' | base64 --decode kubectl获得秘密$(kubectl获得秘密| grep cicd-token | awk'{print $ 1}')-o jsonpath ='{。data.token}'| base64-解码
KUBERNETES_SERVER
will be the string you passed as the --server
flag to kubectl
when you logged in with your cicd
Service Account. You can find this after server:
in the ~/.kube/config
file, or in the file kubernetes-deployment-tutorial-kubeconfig.yaml
downloaded from the DigitalOcean dashboard when you made the initial setup of your Kubernetes cluster.
KUBERNETES_SERVER
将是您使用cicd
服务帐户登录时作为--server
标志传递给kubectl
的字符串。 您可以在server:
之后找到此文件server:
在~/.kube/config
文件中,或在初始设置Kubernetes集群时从DigitalOcean仪表板下载的kubernetes-deployment-tutorial-kubeconfig.yaml
文件中。
KUBERNETES_CLUSTER_CERTIFICATE
should also be available on your ~/.kube/config
file. It’s the certificate-authority-data
field on the clusters
item related to your cluster. It should be a long string; make sure to copy all of it.
KUBERNETES_CLUSTER_CERTIFICATE
也应该在您的~/.kube/config
文件中可用。 这是与您的集群相关的clusters
项上的certificate-authority-data
字段。 它应该是一个长字符串; 确保复制所有内容。
Those environment variables must be defined here because most of them contain sensitive information, and it is not secure to place them directly on the CircleCI YAML config file.
这些环境变量必须在此处定义,因为它们大多数包含敏感信息,将它们直接放在CircleCI YAML配置文件中并不安全。
With CircleCI listening for changes on your repository, and the environment variables configured, it’s time to create the configuration file.
CircleCI侦听存储库中的更改并配置了环境变量后,就该创建配置文件了。
Make a directory called .circleci
inside your sample application repository:
在示例应用程序存储库中.circleci
一个名为.circleci
的目录:
- mkdir ~/do-sample-app/.circleci/ mkdir〜/ do-sample-app / .circleci /
Inside this directory, create a file named config.yml
and open it with your favorite editor:
在此目录中,创建一个名为config.yml
的文件,然后使用您喜欢的编辑器将其打开:
- nano ~/do-sample-app/.circleci/config.yml 纳米〜/ do-sample-app / .circleci / config.yml
Add the following content to the file, making sure to replace dockerhub-username
with your Docker Hub username:
将以下内容添加到文件中,确保将dockerhub-username
替换dockerhub-username
Docker Hub用户名:
version: 2.1
jobs:
build:
docker:
- image: circleci/buildpack-deps:stretch
environment:
IMAGE_NAME: dockerhub-username/do-kubernetes-sample-app
working_directory: ~/app
steps:
- checkout
- setup_remote_docker
- run:
name: Build Docker image
command: |
docker build -t $IMAGE_NAME:latest .
- run:
name: Push Docker Image
command: |
echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin
docker push $IMAGE_NAME:latest
workflows:
version: 2
build-master:
jobs:
- build:
filters:
branches:
only: master
This sets up a Workflow with a single job, called build
, that runs for every commit to the master
branch. This job is using the image circleci/buildpack-deps:stretch
to run its steps, which is an image from CircleCI based on the official buildpack-deps
Docker image, but with some extra tools installed, like Docker binaries themselves.
这将通过一个名为build
作业来设置工作流,该作业将在对master
分支的每次提交中运行。 该工作正在使用图像circleci/buildpack-deps:stretch
运行其步骤,该图像是CircleCI的图像,该图像基于官方的buildpack-deps
Docker映像,但安装了一些额外的工具,例如Docker二进制文件本身。
The workflow has four steps:
工作流程包括四个步骤:
checkout
retrieves the code from GitHub.checkout
从GitHub检索代码。setup_remote_docker
sets up a remote, isolated environment for each build. This is required before you use anydocker
command inside a job step. This is necessary because as the steps are running inside a docker image,setup_remote_docker
allocates another machine to run the commands there.setup_remote_docker
为每个构建设置一个远程隔离环境。 在作业步骤中使用任何docker
命令之前,这是必需的。 这是必需的,因为随着步骤在setup_remote_docker
映像中运行,setup_remote_docker
分配另一台计算机以在其中运行命令。The first
run
step builds the image, as you did previously locally. For that you are using the environment variable you declared inenvironment:
,IMAGE_NAME
(remember to change the highlighted section with your own information).第一次
run
步骤都像,像你一样以前在本地。 为此,您使用的是在environment:
,IMAGE_NAME
声明的环境变量(请记住,请使用您自己的信息更改突出显示的部分)。The last
run
step pushes the image to Dockerhub, using the environment variables you configured on the project settings to authenticate.最后一个
run
步骤使用在项目设置上配置的环境变量进行身份验证,将映像推送到Dockerhub。
Commit the new file to your repository and push the changes upstream:
将新文件提交到您的存储库,并将更改推送到上游:
- cd ~/do-sample-app/ cd〜/ do-sample-app /
- git add .circleci/ git添加.circleci /
- git commit -m "add CircleCI config" git commit -m“添加CircleCI配置”
- git push git推
This will trigger a new build on CircleCI. The CircleCI workflow is going to correctly build and push your image to Docker Hub.
这将触发CircleCI的新构建。 CircleCI工作流将正确构建映像并将其推送到Docker Hub。
Now that you have created and tested your CircleCI workflow, you can set your DOKS cluster to retrieve the up-to-date image from Docker Hub and deploy it automatically when changes are made.
现在,您已经创建并测试了CircleCI工作流程,可以将DOKS集群设置为从Docker Hub检索最新映像,并在进行更改时自动部署它。
步骤8 —更新Kubernetes集群上的部署 (Step 8 — Updating the Deployment on the Kubernetes Cluster)
Now that your application image is being built and sent to Docker Hub every time you push changes to the master
branch on GitHub, it’s time to update your deployment on your Kubernetes cluster so that it retrieves the new image and uses it as a base for deployment.
现在,您每次将更改推送到GitHub上的master
分支时,就已经构建了应用程序映像并将其发送到Docker Hub,现在该更新Kubernetes集群上的部署了,以便它检索新映像并将其用作部署基础。
To do that, first fix one issue with your deployment: it’s currently depending on an image with the latest
tag. This tag does not tell us which version of the image you are using. You cannot easily lock your deployment to that tag because it’s overwritten everytime you push a new image to Docker Hub, and by using it like that you lose one of the best things about having containerized applications: Reproducibility.
为此,请首先解决您的部署中的一个问题:它当前取决于带有latest
标签的映像。 该标签不会告诉我们您所使用的图像版本。 您无法轻松地将部署锁定到该标记,因为每次将新映像推送到Docker Hub时,该标记都会被覆盖,并且由于使用它而失去了容器化应用程序的最佳优势之一:可重复性。
You can read more about that on this article about why depending on Docker latest tag is a anti-pattern.
您可以在本文中阅读有关此内容的更多信息,以了解为什么依赖Docker最新标签是一个反模式 。
To correct this, you first must make some changes to your Push Docker Image
build step in the ~/do-sample-app/.circleci/config.yml
file. Open up the file:
要更正此问题,您首先必须在~/do-sample-app/.circleci/config.yml
文件中对Push Docker Image
构建步骤进行一些更改。 打开文件:
- nano ~/do-sample-app/.circleci/config.yml 纳米〜/ do-sample-app / .circleci / config.yml
Then add the highlighted lines to your Push Docker Image
step:
然后将突出显示的行添加到Push Docker Image
步骤中:
...
- run:
name: Push Docker Image
command: |
echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin
docker tag $IMAGE_NAME:latest $IMAGE_NAME:$CIRCLE_SHA1
docker push $IMAGE_NAME:latest
docker push $IMAGE_NAME:$CIRCLE_SHA1
...
Save and exit the file.
保存并退出文件。
CircleCI has some special environment variables set by default. One of them is CIRCLE_SHA1
, which contains the hash of the commit it’s building. The changes you made to ~/do-sample-app/.circleci/config.yml
will use this environment variable to tag your image with the commit it was built from, always tagging the most recent build with the latest tag. That way, you always have specific images available, without overwriting them when you push something new to your repository.
CircleCI默认情况下设置了一些特殊的环境变量。 其中之一是CIRCLE_SHA1
,其中包含它正在构建的提交的哈希。 您对~/do-sample-app/.circleci/config.yml
将使用此环境变量来标记您的映像以及其生成的提交,始终将最新的生成标记为最新的标记。 这样,您始终可以使用特定的映像,而在将新内容推送到存储库时不会覆盖它们。
Next, change your deployment manifest file to point to that file. This would be simple if inside ~/do-sample-app/kube/do-sample-deployment.yml
you could set your image as dockerhub-username/do-kubernetes-sample-app:$COMMIT_SHA1
, but kubectl
doesn’t do variable substitution inside the manifests when you use kubectl apply
. To account for this, you can use envsubst
. envsubst
is a cli tool, part of the GNU gettext project. It allows you to pass some text to it, and if it finds any variable inside the text that has a matching environment variable, it’s replaced by the respective value. The resulting text is then returned as their output.
接下来,将您的部署清单文件更改为指向该文件。 如果在~/do-sample-app/kube/do-sample-deployment.yml
您可以将映像设置为dockerhub-username /do-kubernetes-sample-app:$COMMIT_SHA1
,但是kubectl
不这样做使用kubectl apply
时清单中的变量替换。 为了解决这个问题,您可以使用envsubst
。 envsubst
是cli工具,是GNU gettext项目的一部分。 It allows you to pass some text to it, and if it finds any variable inside the text that has a matching environment variable, it's replaced by the respective value. The resulting text is then returned as their output.
To use this, you will create a simple bash script which will be responsible for your deployment. Make a new folder called scripts
inside ~/do-sample-app/
:
To use this, you will create a simple bash script which will be responsible for your deployment. Make a new folder called scripts
inside ~/do-sample-app/
:
- mkdir ~/do-sample-app/scripts/ mkdir ~/do-sample-app/scripts/
Inside that folder create a new bash script called ci-deploy.sh
and open it with your favorite text editor:
Inside that folder create a new bash script called ci-deploy.sh
and open it with your favorite text editor:
- nano ~/do-sample-app/scripts/ci-deploy.sh nano ~/do-sample-app/scripts/ci-deploy.sh
Inside it write the following bash script:
Inside it write the following bash script:
#! /bin/bash
# exit script when any command ran here returns with non-zero exit code
set -e
COMMIT_SHA1=$CIRCLE_SHA1
# We must export it so it's available for envsubst
export COMMIT_SHA1=$COMMIT_SHA1
# since the only way for envsubst to work on files is using input/output redirection,
# it's not possible to do in-place substitution, so we need to save the output to another file
# and overwrite the original with that one.
envsubst <./kube/do-sample-deployment.yml >./kube/do-sample-deployment.yml.out
mv ./kube/do-sample-deployment.yml.out ./kube/do-sample-deployment.yml
echo "$KUBERNETES_CLUSTER_CERTIFICATE" | base64 --decode > cert.crt
./kubectl \
--kubeconfig=/dev/null \
--server=$KUBERNETES_SERVER \
--certificate-authority=cert.crt \
--token=$KUBERNETES_TOKEN \
apply -f ./kube/
Let’s go through this script, using the comments in the file. First, there is the following:
Let's go through this script, using the comments in the file. First, there is the following:
set -e
This line makes sure any failed command stops the execution of the bash script. That way if one command fails, the next ones are not executed.
This line makes sure any failed command stops the execution of the bash script. That way if one command fails, the next ones are not executed.
COMMIT_SHA1=$CIRCLE_SHA1
export COMMIT_SHA1=$COMMIT_SHA1
These lines export the CircleCI $CIRCLE_SHA1
environment variable with a new name. If you had just declared the variable without exporting it using export
, it would not be visible for the envsubst
command.
These lines export the CircleCI $CIRCLE_SHA1
environment variable with a new name. If you had just declared the variable without exporting it using export
, it would not be visible for the envsubst
command.
envsubst <./kube/do-sample-deployment.yml >./kube/do-sample-deployment.yml.out
mv ./kube/do-sample-deployment.yml.out ./kube/do-sample-deployment.yml
envsubst
cannot do in-place substitution. That is, it cannot read the content of a file, replace the variables with their respective values, and write the output back to the same file. Therefore, you will redirect the output to another file and then overwrite the original file with the new one.
envsubst
cannot do in-place substitution. That is, it cannot read the content of a file, replace the variables with their respective values, and write the output back to the same file. Therefore, you will redirect the output to another file and then overwrite the original file with the new one.
echo "$KUBERNETES_CLUSTER_CERTIFICATE" | base64 --decode > cert.crt
The environment variable $KUBERNETES_CLUSTER_CERTIFICATE
you created earlier on CircleCI’s project settings is in reality a Base64 encoded string. To use it with kubectl
you must decode its contents and save it to a file. In this case you are saving it to a file named cert.crt
inside the current working directory.
The environment variable $KUBERNETES_CLUSTER_CERTIFICATE
you created earlier on CircleCI's project settings is in reality a Base64 encoded string. To use it with kubectl
you must decode its contents and save it to a file. In this case you are saving it to a file named cert.crt
inside the current working directory.
./kubectl \
--kubeconfig=/dev/null \
--server=$KUBERNETES_SERVER \
--certificate-authority=cert.crt \
--token=$KUBERNETES_TOKEN \
apply -f ./kube/
Finally, you are running kubectl
. The command has similar arguments to the one you ran when you were testing your Service Account. You are calling apply -f ./kube/
, since on CircleCI the current working directory is the root folder of your project. ./kube/
here is your ~/do-sample-app/kube
folder.
Finally, you are running kubectl
. The command has similar arguments to the one you ran when you were testing your Service Account. You are calling apply -f ./kube/
, since on CircleCI the current working directory is the root folder of your project. ./kube/
here is your ~/do-sample-app/kube
folder.
Save the file and make sure it’s executable:
Save the file and make sure it's executable:
- chmod +x ~/do-sample-app/scripts/ci-deploy.sh chmod +x ~/do-sample-app/scripts/ci-deploy.sh
Now, edit ~/do-sample-app/kube/do-sample-deployment.yml
:
Now, edit ~/do-sample-app/kube/do-sample-deployment.yml
:
- nano ~/do-sample-app/kube/do-sample-deployment.yml nano ~/do-sample-app/kube/do-sample-deployment.yml
Change the tag of the container image value to look like the following one:
Change the tag of the container image value to look like the following one:
# ...
containers:
- name: do-kubernetes-sample-app
image: dockerhub-username/do-kubernetes-sample-app:$COMMIT_SHA1
ports:
- containerPort: 80
name: http
Save and close the file. You must now add some new steps to your CI configuration file to update the deployment on Kubernetes.
保存并关闭文件。 You must now add some new steps to your CI configuration file to update the deployment on Kubernetes.
Open ~/do-sample-app/.circleci/config.yml
on your favorite text editor:
Open ~/do-sample-app/.circleci/config.yml
on your favorite text editor:
- nano ~/do-sample-app/.circleci/config.yml nano ~/do-sample-app/.circleci/config.yml
Write the following new steps, right below the Push Docker Image
one you had before:
Write the following new steps, right below the Push Docker Image
one you had before:
...
- run:
name: Install envsubst
command: |
sudo apt-get update && sudo apt-get -y install gettext-base
- run:
name: Install kubectl
command: |
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
chmod u+x ./kubectl
- run:
name: Deploy Code
command: ./scripts/ci-deploy.sh
The first two steps are installing some dependencies, first envsubst
, and then kubectl
. The Deploy Code
step is responsible for running our deploy script.
The first two steps are installing some dependencies, first envsubst
, and then kubectl
. The Deploy Code
step is responsible for running our deploy script.
To make sure the changes are really going to be reflected on your Kubernetes deployment, edit your index.html
. Change the HTML to something else, like:
To make sure the changes are really going to be reflected on your Kubernetes deployment, edit your index.html
. Change the HTML to something else, like:
<!DOCTYPE html>
<title>DigitalOcean</title>
<body>
Automatic Deployment is Working!
</body>
Once you have saved the above change, commit all the modified files to the repository, and push the changes upstream:
Once you have saved the above change, commit all the modified files to the repository, and push the changes upstream:
- cd ~/do-sample-app/ cd ~/do-sample-app/
- git add --all git添加--all
- git commit -m "add deploy script and add new steps to circleci config" git commit -m "add deploy script and add new steps to circleci config"
- git push git push
You will see the new build running on CircleCI, and successfully deploying the changes to your Kubernetes cluster.
You will see the new build running on CircleCI, and successfully deploying the changes to your Kubernetes cluster.
Wait for the build to finish, then run the same command you ran previously:
Wait for the build to finish, then run the same command you ran previously:
- kubectl port-forward $(kubectl get pod --selector="app=do-kubernetes-sample-app" --output jsonpath='{.items[0].metadata.name}') 8080:80 kubectl port-forward $(kubectl get pod --selector="app=do-kubernetes-sample-app" --output jsonpath='{.items[0].metadata.name}') 8080:80
Make sure everything is working by opening your browser on the URL localhost:8080
or by making a curl
request to it. It should show the updated HTML:
Make sure everything is working by opening your browser on the URL localhost:8080
or by making a curl
request to it. It should show the updated HTML:
- curl localhost:8080 curl本地主机:8080
You will receive the following output:
您将收到以下输出:
Output
<!DOCTYPE html>
<title>DigitalOcean</title>
<body>
Automatic Deployment is Working!
</body>
Congratulations, you have set up automated deployment with CircleCI!
Congratulations, you have set up automated deployment with CircleCI!
结论 (Conclusion)
This was a basic tutorial on how to do deployments to DigitalOcean Kubernetes using CircleCI. From here, you can improve your pipeline in many ways. The first thing you can do is create a single build
job for multiple deployments, each one deploying to different Kubernetes clusters or different namespaces. This can be extremely useful when you have different Git branches for development/staging/production environments, ensuring that the deployments are always separated.
This was a basic tutorial on how to do deployments to DigitalOcean Kubernetes using CircleCI. From here, you can improve your pipeline in many ways. The first thing you can do is create a single build
job for multiple deployments, each one deploying to different Kubernetes clusters or different namespaces. This can be extremely useful when you have different Git branches for development/staging/production environments, ensuring that the deployments are always separated.
You could also build your own image to be used on CircleCI, instead of using buildpack-deps
. This image could be based on it, but could already have kubectl
and envsubst
dependencies installed.
You could also build your own image to be used on CircleCI, instead of using buildpack-deps
. This image could be based on it, but could already have kubectl
and envsubst
dependencies installed.
If you would like to learn more about CI/CD on Kubernetes, check out the tutorials for our CI/CD on Kubernetes Webinar Series, or for more information about apps on Kubernetes, see Modernizing Applications for Kubernetes.
If you would like to learn more about CI/CD on Kubernetes, check out the tutorials for our CI/CD on Kubernetes Webinar Series , or for more information about apps on Kubernetes, see Modernizing Applications for Kubernetes .