We previously looked at how to deploy a Docker application to Google Cloud Platform (GCP) with Google Container Engine(GKE) using Kubernetes.
我们之前曾研究过如何使用Kubernetes使用Google Container Engine(GKE)将Docker应用程序部署到Google Cloud Platform(GCP)。
This gave us the opportunity to appreciate the role that Kubernetes plays in managing/orchestrating GKE clusters with ease.
这使我们有机会了解Kubernetes在轻松管理/协调GKE集群中所扮演的角色。
One thing that we missed out on was how deploying Docker containers pans out when working in a team that employs Continuous Integration / Continuous Deployment (CI/CD) where frequent updates of an application are made by each member of the team and, well, continously deployed to staging or production.
我们错过的一件事是,在使用持续集成/持续部署(CI / CD)的团队中工作时,部署Docker容器的工作如何顺利进行,该团队的每个成员都对应用程序进行频繁的更新,并且不断地部署到阶段或生产。
As you would imagine, things can quickly get out of hand when each team member individually pushes their own version of the image to the Google Container Registry.
就像您想象的那样,当每个团队成员将自己的图像版本分别推送到Google Container Registry时,事情很快就会失控。
The image tags may conflict, be out of date or buggy images may be pushed to production and the world as we know it would come to a stop.
图片标签可能会发生冲突,过时或有问题的图片可能会投入生产,而我们所知道的世界将会停止。
CircleCI的持续部署 ( Continuous Deployment with CircleCI )
CircleCI is one of the most popular CI/CD tools in use today alongside TravisCI and Codeship. We wil be using CircleCI to continuously deploy our application just like we would in a distributed team.
除 TravisCI和Codeship之外,CircleCI是当今使用最广泛的CI / CD工具之一。 我们将使用CircleCI来持续部署我们的应用程序 ,就像在分布式团队中一样。
To achieve this, we will do the following:
为此,我们将执行以下操作:
- Write tests for our application. 为我们的应用编写测试。
- Configure CircleCI to authenticate with our GKE cluster. 配置CircleCI以通过我们的GKE集群进行身份验证。
- Add a circle.yml configuration file for the application deployment process. 为应用程序部署过程添加一个circle.yml配置文件。
- If the tests pass on CircleCI, update the containerized app to GKE. 如果测试通过CircleCI,请将容器化的应用更新为GKE。
Sounds good? Sweet! Let's get started!
听起来不错? 甜! 让我们开始吧!
添加测试 ( Adding Tests )
We'll use supertest to test the routes in index.js
in the test and mocha test framework to run the test.
我们将在测试和Mocha测试框架中使用supertest测试index.js
中的路由以运行测试。
npm install --save-dev mocha supertest
Once installed, create test/index_test.js
in the application route and add the test below.
安装后,在应用程序路由中创建test/index_test.js
并在下面添加测试。
test/index_test.js
测试/ index_test.js
//Load supertest and the app instance.
const request = require('supertest');
const app = require('../index').app;
describe('Index Tests', () => {
describe('GET /', () => {
//Should return status code 200 with JSON message: welcome to root
it('Should return root message', (done) => {
request(app)
.get('/')
.expect(200)
.expect(JSON.stringify('welcome to root'))
.end(done);
});
});
});
The test makes a GET request to the root of our project and asserts that a JSON string is given back with a 200 status code. Add the test command in the scripts section of our package,json
file.
该测试向我们项目的根目录发出GET请求,并断言返回了JSON字符串并带有200状态代码。 在我们的package,json
文件的scripts部分中添加test命令。
package.json
package.json
...
"scripts": {
"test": "node_modules/.bin/mocha",
"start": "node index.js"
},
...
View the test result by running npm test
. You should get the following.
通过运行npm test
查看测试结果。 您应该获得以下内容。
整合CircleCI (Integrating CircleCI)
With our tests passing, let's add a circle.yml
file and instruct CircleCI how to run our tests using mocha. Luckily, every CircleCI build comes preinstalled with mocha so all we need to do is instruct it to use mocha.
通过测试之后,让我们添加一个circle.yml
文件,并指示CircleCI如何使用mocha运行我们的测试。 幸运的是,每个CircleCI构建都预装了Mocha,因此我们需要做的就是指示它使用Mocha。
Note that by default, CircleCI will try to run npm test
.
请注意,默认情况下,CircleCI将尝试运行npm test
。
test:
override:
- mocha
将项目添加到CircleCI (Add Project to CircleCI)
Once everything is set up, push the code to a Gihub repository, login to CircleCI with Github then go to CircleCI > Add Projects and build your repository. If everything is correctly set up, you should have a succesful build.
一切设置完成后,将代码推送到Gihub存储库,使用Github登录到CircleCI,然后转到CircleCI>添加项目并构建您的存储库。 如果一切设置正确,则应该成功完成构建。
With this, let's make CircleCI do all the heavy lifting for us.
这样,让CircleCI为我们完成所有繁重的工作。
在CircleCI上验证GKE集群 ( Authenticating The GKE Cluster on CircleCI )
The objective of this section is to simply let CircleCI know that we own the scotch-cluster
. When creating the Deployments and Services locally, we followed the following protocol:
本节的目的是简单地让CircleCI知道我们拥有scotch scotch-cluster
。 在本地创建部署和服务时,我们遵循以下协议:
- Login to Google - Using the
gcloud init
in the initial setup orgcloud auth login
later on. 登录到gcloud init
在初始设置中使用gcloud init
或稍后再使用gcloud auth login
。 - Set the default project -
gcloud config set project scotch-155622
设置默认项目gcloud config set project scotch-155622
- Set the default cluster -
gcloud config set container/cluster scotch-cluster
设置默认集群gcloud config set container/cluster scotch-cluster
- Get the cluster credentials -
gcloud container clusters get-credentials scotch-cluster --zone us-central1-a --project scotch-155622
获取集群凭证gcloud container clusters get-credentials scotch-cluster --zone us-central1-a --project scotch-155622
- Gone ahead to be awesome. 变得很棒。
But how do we authenticate CircleCI? We cannot exactly use gcloud auth login
can we? That would mean allowing access to our gmail accounts. Sounds wrong, doesn't it?
但是我们如何认证CircleCI? 我们不能完全使用gcloud auth login
吗? 那意味着允许访问我们的Gmail帐户。 听起来不对,不是吗?
And it is! Gladly, Google Cloud Platform provides Service Accounts which come in handy.
是的! 很高兴地,Google Cloud Platform提供了方便的服务帐户 。
A service account is a special account that can be used by services and applications running on your Google Compute Engine instance to interact with other Google Cloud Platform APIs. Applications can use service account credentials to authorize themselves to a set of APIs and perform actions within the permissions granted to the service account and virtual machine instance.
服务帐户是一个特殊帐户,供您在Google Compute Engine实例上运行的服务和应用程序用来与其他Google Cloud Platform API进行交互的帐户。 应用程序可以使用服务帐户凭据来授权自己使用一组API,并在授予服务帐户和虚拟机实例的权限内执行操作。
Let's set up our service account!
让我们设置我们的服务帐户!
生成服务帐户 (Generating a Service Account)
To create a new service account, go to the Service Accounts Page and select your project. You will be required to generate a Service account ID / email here. Go ahead and enter a name for the account and select a role for the service account, in our case, Service Account Actor
.
要创建一个新的服务帐户,请转到“ 服务帐户”页面并选择您的项目。 您将需要在此处生成服务帐户ID /电子邮件。 继续,输入帐户名称,然后选择服务帐户的角色,在本例中为Service Account Actor
。
You can also create a service account ID using the gcloud command.
您还可以使用gcloud命令创建服务帐户ID。
gcloud iam service-accounts create scotch-sa --display-name"Scotch Service Account"
Once the service account is created, a JSON file will be downloaded to your local system. We will use that in the next section.
创建服务帐户后,会将JSON文件下载到您的本地系统。 我们将在下一部分中使用它。
环境变量 (Environment Variables)
It's always easier to set up frequently used data as environment variables in any project. Better yet, if some of these variables are sensitive, like our service account token, they are best stored away from our codebase.
在任何项目中,将常用数据设置为环境变量总是更容易。 更好的是,如果其中一些变量是敏感的,例如我们的服务帐户令牌,则最好将其存储在远离我们的代码库的位置。
To get started, let's add the project ID, cluster name, deployment name, container name and the compute zone of our cluster in circle.yml
, these are the less sensitive details we can afford to add our configuration file.
首先,让我们在circle.yml
添加项目ID,集群名称,部署名称,容器名称和集群的计算区域,这些是我们可以负担得起的添加配置文件的较不敏感的细节。
circle.yml
circle.yml
machine:
environment:
PROJECT_ID: scotch-155622
CLUSTER_NAME: scotch-cluster
COMPUTE_ZONE: us-central1-a
#As specified in Deployment.yml
DEPLOYMENT_NAME: scotch-dep
CONTAINER_NAME: node-app
test:
override:
- mocha
Simple and neat.
简单而整洁。
Now to store the service account JSON file as an environment variable. It would be catastrophic if we decided to add it in the publicly accessible circle.yml file. Lucky for us, CircleCI allows us to set environment variables for each project.
现在将服务帐户JSON文件存储为环境变量。 如果我们决定将其添加到可公开访问的circle.yml文件中,将是灾难性的。 对我们来说幸运的是,CircleCI允许我们为每个项目设置环境变量。
First, let's encode our JSON file into base64 format so that we can store it as a string. For Linux and OS X users, run the following command to decode and copy the encoded string:
首先,让我们将JSON文件编码为base64格式,以便我们可以将其存储为字符串。 对于Linux和OS X用户,运行以下命令以解码和复制编码的字符串:
base64 scotch-2efb8709c63d.json| pbcopy
Next, go to CircleCI > Builds > Repository settings > Environment Variables > Add Variable and add the service key and Account ID.
接下来,转到CircleCI>构建>存储库设置>环境变量>添加变量,然后添加服务密钥和帐户ID。
We now have access to $SERVICE_KEY
and $ACCOUNT_ID
in our CircleCI build.
现在,我们可以在CircleCI版本中访问$SERVICE_KEY
和$ACCOUNT_ID
。
提供我们的部署环境 (PROVISIONING OUR DEPLOYMENT ENVIRONMENT)
Just like we did in our local environment, we need to make sure that gcloud
and kubectl
command-line tools are installed as well as good old Docker. Once again, CircleCI comes pre-installed with both, we just have to make sure they are up to date before we do anything.
就像我们在本地环境中所做的一样,我们需要确保已安装gcloud
和kubectl
命令行工具以及良好的旧Docker。 再一次,CircleCI都预装了两者,我们只需要确保它们是最新的就可以进行任何操作。
Once they are updated, We need to:-
更新后,我们需要:-
- Check for any changes in the deployment branch (master in our case) 检查部署分支中的任何更改(在本例中为master )
- Decode the service account and authenticate the build 解码服务帐户并验证构建
- Set the default project, cluster and compute zone 设置默认项目,群集和计算区域
- Get the credentials for the
scotch-cluster
获取scotch-cluster
的凭据 - Start Docker 启动Docker
circle.yml
circle.yml
machine:
environment:
PROJECT_ID: scotch-155622
CLUSTER_NAME: scotch-cluster
COMPUTE_ZONE: us-central1-a
#As specified in Deployment.yml
DEPLOYMENT_NAME: scotch-dep
CONTAINER_NAME: node-app
test:
override:
- mocha
#Ensure that gcloud and kubectl are updated.
dependencies:
pre:
- sudo /opt/google-cloud-sdk/bin/gcloud --quiet components update --version 120.0.0
- sudo /opt/google-cloud-sdk/bin/gcloud --quiet components update --version 120.0.0 kubectl
deployment:
production:
branch: master
commands:
# Save the string to a text file
- echo $SERVICE_KEY > key.txt
# Decode the Service Account
- base64 -i key.txt -d > ${HOME}/gcloud-service-key.json
# Authenticate CircleCI with the service account file
- sudo /opt/google-cloud-sdk/bin/gcloud auth activate-service-account ${ACCOUNT_ID} --key-file ${HOME}/gcloud-service-key.json
# Set the default project
- sudo /opt/google-cloud-sdk/bin/gcloud config set project $PROJECT_ID
# Set the default container
- sudo /opt/google-cloud-sdk/bin/gcloud --quiet config set container/cluster $CLUSTER_NAME
# Set the compute zone
- sudo /opt/google-cloud-sdk/bin/gcloud config set compute/zone $COMPUTE_ZONE
# Get the cluster credentials.
- sudo /opt/google-cloud-sdk/bin/gcloud --quiet container clusters get-credentials $CLUSTER_NAME
# Start good old Docker
- sudo service docker start
推出应用程序更新 ( Rolling Out Application Updates )
更新circle.yml配置 (Updating circle.yml configuration)
For those of us with a hankering to finally get to the good stuff, welcome to Docker town! We are about to get this container rolling. Up until now, we have been preparing our Continous Deployment environment but we are yet to actually even build an image. Fret not!
对于那些渴望最终获得好东西的人,欢迎来到Docker小镇! 我们将使这个容器滚动。 到目前为止,我们一直在准备我们的持续部署环境,但实际上还没有建立映像。 不用担心!
If you recall where we last left things, when deploying from our local system, the last step of our journey involves the following:
如果您还记得我们最后剩下的东西,那么从本地系统进行部署时,旅程的最后一步涉及以下内容:
- Building a Docker image from our application and correctly tagging it. 从我们的应用程序构建一个Docker映像并正确标记它。
- Pushing the Docker image to the GCP Container Registry. 将Docker映像推送到GCP容器注册表。
Well let's add one more step to that grand process. Once a new image is pushed, we will need to set it as the latest image from which our Docker container, the Kubernetes Deployment is run from.
好吧,让我们在这一宏伟的过程中再增加一步。 推送新映像后,我们需要将其设置为运行Docker容器Kubernetes Deployment的最新映像。
Note that we are using $CIRCLE_SHA1
which is CircleCI's environment variable of the latest git commit hash since it will always be unique. You can however adopt any tagging model that your team fancies such as Semantic Versioning.
请注意,我们使用的是$CIRCLE_SHA1
,它是CircleCI最新git commit哈希的环境变量,因为它始终是唯一的。 但是,您可以采用团队喜欢的任何标记模型,例如语义版本控制。
Here is a look at the final circle.yml
configuration in the commands section
这是命令部分的最后一个circle.yml
配置
dependencies:
.
.
.
# Build a Docker image and use the Github commit hash ($CIRCLE_SHA1) as the tag
- docker build -t gcr.io/${PROJECT_ID}/node-app:$CIRCLE_SHA1 .
# Push the Image to the GCP Container Registry
- sudo /opt/google-cloud-sdk/bin/gcloud docker -- push gcr.io/${PROJECT_ID}/node-app:$CIRCLE_SHA1
# Update the default image for the deployment
- sudo /opt/google-cloud-sdk/bin/kubectl set image deployment/${DEPLOYMENT_NAME} ${CONTAINER_NAME}=gcr.io/${PROJECT_ID}/node-app:$CIRCLE_SHA1
This will recreate the pods and ensure the user has the most updated application running without any impact or downtime on their side. This is achieved by destroying one pod at a time before moving on to the next one.
这将重新创建Pod,并确保用户正在运行最新的应用程序,而不会对其造成任何影响或停机。 这是通过一次摧毁一个吊舱,然后再移至下一个吊舱来实现的。
Here is a snapshot of the pods recreation process. Notice how fast the pods come alive!
这是豆荚休闲过程的快照。 请注意豆荚存活的速度!
进行应用程序更新 (Making an application update)
To see the update in action, let's add a new route in our application.
要查看实际的更新,让我们在应用程序中添加一条新路由。
index.js
index.js
...
app.get('/baz', (req, res) => {
res.status(200).json('Baz!');
});
...
Commit the changes and push to Github. Once the CircleCI build is succesful, visit the /baz route.
提交更改并推送到Github。 一旦CircleCI构建成功,请访问/ baz路线。
Works like a charm!
奇迹般有效!
Take a look at the Container Registry, and you'll notice that we have a swanky new image with a newer tag.
看一下Container Registry,您会注意到我们有一个带有新标签的时髦新图像。
结论 ( Conclusion )
In this article, we were able to continously deploy our containerized application with CircleCI builds to Google Cloud Platform's Google Container Engine (GKE) with ease. There is still alot more out there to learn on GCP.
在本文中,我们能够轻松地将CircleCI构建的容器化应用程序连续部署到Google Cloud Platform的Google Container Engine(GKE)。 关于GCP的知识还有很多。
Go forth and conquer!
来征服!