本教程包括:
- 使用CircleCI的轨道创建一个持续的集成管道
- 在你推送代码到你的 repo 后触发管道
- 在Azure Kubernetes服务上部署一个Node.js应用程序
容器和微服务已经彻底改变了在云上部署应用程序的方式。自2014年推出以来,Kubernetes已经成为容器编排工具的事实标准。
在本教程中,你将学习如何通过持续集成和持续部署(CI/CD)在Azure Kubernetes服务(AKS)上部署一个Node.js应用程序。你将使用CircleCI orbs创建一个CI/CD管道,CircleCI orbs是可重复使用的YAML配置包,它将重复的配置部分浓缩成一行代码。在你把代码推送到GitHub仓库后,你的管道将被自动触发。使用这种自动化,你将始终有最新版本的应用程序在Kubernetes集群上运行。
克隆Node.js应用程序
在本教程中,你的主要重点是在Kubernetes上部署应用程序。因此,你可以直接克隆 Node.js应用程序到你的GitHub上,然后继续完成剩下的过程。
要克隆该项目,请运行。
git clone https://github.com/CIRCLECI-GWP/nodejs-aks-deploy.git
这个仓库包含Node.js应用的代码,以及我们将在本教程中创建的所有YAML文件。
Node.js应用程序住在app.js 文件中。
const express = require("express");
const path = require("path");
const morgan = require("morgan");
const bodyParser = require("body-parser");
/* eslint-disable no-console */
const port = process.env.PORT || 1337;
const app = express();
app.use(morgan("dev"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: "true" }));
app.use(bodyParser.json({ type: "application/vnd.api+json" }));
app.use(express.static(path.join(__dirname, "./")));
app.get("*", (req, res) => {
res.sendFile(path.join(__dirname, "./index.html"));
});
app.listen(port, (err) => {
if (err) {
console.log(err);
} else {
console.log(`App at: http://localhost:${port}`);
}
});
module.exports = app;
从这段代码中得到的关键信息是应用程序将运行的端口号,即1337 。
你可以通过首先安装依赖项在本地运行该应用程序。在项目的根目录下,输入。
npm install
然后用该命令运行该应用程序。
node app.js
现在应用程序应该已经启动并运行在http://localhost:1337 。
现在在你的GitHub账户上为这个项目创建一个新的仓库,并将项目推送到你刚刚创建的仓库中。
容器化Node.js应用程序
要将应用程序部署到Kubernetes,你必须先将其容器化。使用Docker作为容器运行时工具,创建一个Docker文件。Dockerfile是一个文本文件,包含了用户可以在命令行上调用的所有命令,以组装一个镜像。
在项目的根目录下创建一个新文件,命名为Dockerfile 。在该文件中复制以下内容。
# Set the base image to use for subsequent instructions
FROM node:alpine
# Set the working directory for any subsequent ADD, COPY, CMD, ENTRYPOINT,
# or RUN instructions that follow it in the Dockerfile
WORKDIR /usr/src/app
# Copy files or folders from source to the dest path in the image's filesystem.
COPY package.json /usr/src/app/
COPY . /usr/src/app/
# Execute any commands on top of the current image as a new layer and commit the results.
RUN npm install --production
# Define the network ports that this container will listen to at runtime.
EXPOSE 1337
# Configure the container to be run as an executable.
ENTRYPOINT ["npm", "start"]
如果你安装了Docker,你可以在本地构建并运行容器进行测试。
在本教程的后面,你将学习如何用CircleCI orbs来自动完成这个过程。
要构建和标记容器,你可以输入。
docker build -t nodejs-aks-app:latest .
从你的终端运行这个命令,确认镜像已经成功创建。
docker images
然后用该命令运行容器。
docker run -it -p 1337:1337 nodejs-aks-app:latest
应用程序现在应该已经启动并运行在http://127.0.0.1:1337 。
提交并推送修改内容到你的GitHub仓库。
配置Kubernetes清单以进行部署
要在Kubernetes上部署容器,你需要配置Kubernetes以纳入运行应用程序所需的所有设置。Kubernetes使用YAML进行配置。
在项目的根目录下创建一个名为manifests 的目录。
然后,在新创建的文件夹中创建以下文件。
namespace.yamldeployment.yamlservice.yamlkustomization.yaml
namespace.yaml 在Kubernetes中,命名空间提供了一种机制,用于隔离单个集群中的资源组。
文件的内容如下。
apiVersion: v1
kind: Namespace
metadata:
name: nodejs
labels:
name: nodejs
这个文件将在Kubernetes集群内创建一个名为nodejs 的命名空间。所有的资源都将在这个命名空间中创建。
Kubernetes部署管理集群上运行的无状态服务。它们的目的是保持一组相同的pods运行,并以可控的方式升级它们--默认执行滚动更新。deployment.yaml 的内容如下。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nodejs
namespace: nodejs
labels:
app: nodejs
spec:
replicas: 3
selector:
matchLabels:
app: nodejs
template:
metadata:
labels:
app: nodejs
spec:
nodeSelector:
"beta.kubernetes.io/os": linux
containers:
- name: nodejs-aks-app
image: nodejs-aks-app
ports:
- name: http
containerPort: 1337
以下是这段代码的主要收获。
containerPort是应用程序将在其上运行的端口。- 容器
image,是将在Kubernetes集群上的所述命名空间中拉出并部署的Docker镜像。
Kubernetes服务是一个抽象概念,它定义了一组逻辑上的pod和一个访问它们的策略。你需要一个类型为LoadBalancer 的Kubernetes服务,以使部署能够被外部世界所访问。service.yaml 的内容如下。
apiVersion: v1
kind: Service
metadata:
name: nodejs
namespace: nodejs
labels:
app: nodejs
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 1337
selector:
app: nodejs
以下是这段代码的主要内容。
targetPort是容器的端口。port是应用程序将要运行的地方。type是服务的类型(本例中为 )。LoadBalancer
为了在Kubernetes集群上部署应用程序的最新版本,必须对资源进行定制,以保持更新的信息。这是由Kustomize管理的,它是定制Kubernetes配置的工具。kustomization.yaml 的内容如下。
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- namespace.yaml
namespace: nodejs
images:
- name: nodejs-aks-app
newName: nodejs-aks-app
newTag: v1
这里的关键是,在持续集成过程中,newName 和newTag 将自动更新最新的Docker镜像信息。
提交并推送这些文件到你之前克隆的GitHub仓库。
启动Azure Kubernetes服务(AKS)集群
现在你已经准备好在AKS集群上部署应用程序了。要创建AKS集群,你需要一个Microsoft Azure账户,并在你的电脑上安装Azure CLI。CLI应该连接到你的Azure账户。
完成后,你可以在Azure CLI的帮助下启动AKS集群。
用以下命令创建一个资源组。
az group create --name NodeRG --location eastus
用这个命令启动一个双节点集群。
az aks create --resource-group NodeRG --name NodeCluster --node-count 2 --enable-addons http_application_routing
注意: 如果你之前在系统中生成了任何SSH密钥,你需要在上述命令中添加一个可选的参数--generate-ssh-keys 。如果缺少SSH公钥和私钥文件,这将自动生成这些文件。这些密钥将被存储在~/.ssh 目录中。
AKS集群将需要10-15分钟来启动。
创建持续集成管道
本教程的目的是展示如何通过CI/CD管道在Kubernetes上部署应用程序。该管道应触发构建容器的过程,将其推送到Dockerhub并在集群上部署。
为了创建CI/CD管道,你将使用与你的GitHub账户集成的CircleCI。CircleCI配置文件(config.yml)位于项目根目录下的.circleci 目录中。该配置的路径是.circleci/config.yml 。
下面是config.yml 的内容。
version: 2.1
orbs:
docker: circleci/docker@2.1.1
azure-aks: circleci/azure-aks@0.3.0
kubernetes: circleci/kubernetes@1.3.0
jobs:
aks-deploy:
executor: azure-aks/default
parameters:
cluster-name:
description: |
Name of the AKS cluster
type: string
resource-group:
description: |
Resource group that the cluster is in
type: string
steps:
- checkout
- run:
name: Pull Updated code from repo
command: git pull origin $CIRCLE_BRANCH
- azure-aks/update-kubeconfig-with-credentials:
cluster-name: << parameters.cluster-name >>
install-kubectl: true
perform-login: true
resource-group: << parameters.resource-group >>
- kubernetes/create-or-update-resource:
resource-file-path: manifests/$APP_NAME.yaml
resource-name: kustomization/$APP_NAME
bump-docker-tag-kustomize:
docker:
- image: cimg/base:stable
steps:
- run:
name: Install kustomize
command: |
URL=https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize/v4.5.2/kustomize_v4.5.2_linux_amd64.tar.gz
curl -L $URL | tar zx
[ -w /usr/local/bin ] && SUDO="" || SUDO=sudo
$SUDO chmod +x ./kustomize
$SUDO mv ./kustomize /usr/local/bin
- checkout
- run:
name: Bump Docker Tag
command: |
cd manifests
kustomize edit set image $APP_NAME=$DOCKER_LOGIN/$APP_NAME:$CIRCLE_SHA1
kustomize build . > $APP_NAME.yaml
- add_ssh_keys:
fingerprints:
- "$SSH_FINGERPRINT"
- run:
name: Commit & Push to GitHub
command: |
git config user.email "$GITHUB_EMAIL"
git config user.name "CircleCI User"
git checkout $CIRCLE_BRANCH
git add manifests/$APP_NAME.yaml
git add manifests/kustomization.yaml
git commit -am "Bumps docker tag [skip ci]"
git push origin $CIRCLE_BRANCH
workflows:
Deploy-App-on-AKS:
jobs:
- docker/publish:
image: $DOCKER_LOGIN/$APP_NAME
tag: $CIRCLE_SHA1,latest
- bump-docker-tag-kustomize:
requires:
- docker/publish
- aks-deploy:
cluster-name: $CLUSTER_NAME
resource-group: $RESOURCE_GROUP
requires:
- bump-docker-tag-kustomize
CI工作流程由三个工作组成。
docker/publish构建容器并将其推送到Docker Hub。bump-docker-tag-kustomize更新Docker Image Tag并生成一个综合的Kubernetes配置文件。aks-deploy在AKS集群上应用该配置文件。
这个工作流程广泛地使用了CircleCI orbs,它是开源的、可共享的、可参数化的、可重用的配置元素包,包括作业、命令和执行器。这些orbs被直接使用或用于创建自定义作业。
提交并推送修改内容到你的GitHub仓库。
在CircleCI上设置项目
将您的应用程序部署到AKS的下一步是将您GitHub仓库中的应用程序连接到CircleCI。
进入您的CircleCI仪表板,选择左侧面板上的项目标签。点击与包含代码的GitHub仓库相对应的Set Up Project按钮。在本教程中,该仓库被命名为nodejs-aks-deploy 。

当提示你选择config.yml文件时,选择Fastest选项并输入main 作为分支名称。CircleCI将自动定位到config.yml 文件。点击Set Up Project。

工作流程将开始运行,但很快它就会把status 显示为Failed 。这是因为你仍然需要在CircleCI项目设置中设置一个用户密钥和配置环境变量。
要设置用户密钥,从项目设置页面的左侧面板选择SSH密钥选项。在User Key部分,点击Authorize with GitHub,CircleCI会在工作流程的执行过程中使用该用户密钥,代表仓库所有者向您的GitHub账户推送更改。

要配置环境变量,从项目设置页面的左侧面板中选择环境变量选项。选择添加环境变量。接下来,键入环境变量和你希望分配给它的值。

文件中使用的环境变量有。
APP_NAME是容器镜像名称( )。nodejs-aks-appAZURE_PASSWORD是你的Azure帐户密码。AZURE_USERNAME是你的Azure帐户用户名。CLUSTER_NAME是AKS集群名称( )。NodeClusterDOCKER_LOGIN是你的Docker Hub用户名。DOCKER_PASSWORD是你的Docker Hub密码。GITHUB_EMAIL是你的GitHub账户的电子邮件地址。RESOURCE_GROUP是AKS资源组 ( )。NodeRGSSH_FINGERPRINT是用于向GitHub推送更新的Docker标签的用户密钥的SSH Fingerprint。
注意: 要找到SSH_FINGERPRINT ,请进入项目设置,从侧边栏选择SSH密钥。向下滚动到用户密钥部分,然后复制该密钥。这个密钥只有在你点击 "用GitHub授权"按钮后才会显示。
现在你可以重新运行工作流程了。这次status 是Success 。

你还会发现另一条流水线上的status 是Not Run 。之所以出现这种情况,是因为在提交信息中包括[skip ci] 这一术语,明确指示CircleCI在向GitHub提交更新的配置文件时跳过该管道。这就保护了工作流程不会出现自我触发的无休止循环。
在AKS上访问应用程序
当工作流重新运行时,收到一个成功的status ,这意味着应用程序已经被部署在AKS集群上。要访问该应用程序,你需要集群的外部IP地址。
要找到External-IP ,你可以再次使用Azure CLI。
配置kubectl ,用这个命令连接到AKS。
az aks get-credentials --resource-group NodeRG --name NodeCluster
你在nodejs 命名空间中创建了所有的资源,所以使用下面的命令来获取该命名空间中的所有资源。
kubectl get all --namespace nodejs
复制External-IP 对应的service/nodejs 。

你可以在http://<EXTERNAL-IP> 上访问该应用程序。在我的例子中,那就是http://20.102.11.73/ 。

总结
恭喜你!你已经达到了本教程的终点。你已经到达了本教程的终点。在本教程中,你学到了如何开发一个自动化CI管道,以便在Kubernetes集群上连续部署你的应用程序。一旦管道配置正确,对应用程序代码的任何修改都会立即反映在应用程序的URL上。没有必要再手动配置和部署Kubernetes上的应用程序了。你可以改变环境变量的值,将CircleCI配置文件用于类似的应用程序。