在这篇文章里,我们看看如何将Azure-Samples/aks-store-demo运行到Docker Compose或带有Score的Kubernetes集群,并看看它如何让开发体验更简单!
名为 Azure-Samples/aks-store-demo 的仓库是一个很好的例子,展示了如何用不同编程语言部署微服务容器,并与 RabbitMQ 和 MongoDB 等数据库通信。此外,还可选择部署一个与 OpenAI 或 Azure OpenAI 通信的容器化应用程序。
非常适合学习!即使这些应用是由微软员工创建和维护的,你也可以将它们部署到任何 Kubernetes 集群,甚至可以直接使用 Docker 和 Docker Compose 在本地运行。
可以参考Azure 官方文档中的教程,了解如何使用 Docker Compose 部署这些示例应用。
你可以找到第一个 [docker-compose-quickstart.yml](https://github.com/Azure-Samples/aks-store-demo/blob/main/docker-compose-quickstart.yml)
文件,它包含了 order-service
、product-service
、store-front
和 rabbitmq
。还有一个 [docker-compose.yml](https://github.com/Azure-Samples/aks-store-demo/blob/main/docker-compose.yml)
文件,它包含更多服务,例如 makeline-service
、store-admin
、virtual-customer
、virtual-worker
、ai-service
和 mongodb
。
让我们来关注 makeline-service
, 其两个依赖项 rabbitmq
以及 mongodb
。
services: mongodb: image: mongo:6.0.6 container_name: 'mongo' restart: always ports: - 27017:27017 healthcheck: test: ["CMD", "mongosh", "--eval", "db.runCommand('ping').ok"] # 检查 MongoDB 是否存活 interval: 30s timeout: 10s retries: 5 networks: - 后端服务 rabbitmq: image: rabbitmq:3.13.2-management-alpine container_name: 'rabbitmq' restart: always environment: - "RABBITMQ_DEFAULT_USER=username" - "RABBITMQ_DEFAULT_PASS=password" # 设置 RabbitMQ 默认用户名和密码 ports: - 15672:15672 - 5672:5672 healthcheck: test: ["CMD", "rabbitmqctl", "status"] # 检查 RabbitMQ 是否存活 interval: 30s timeout: 10s retries: 5 volumes: - ./rabbitmq_enabled_plugins:/etc/rabbitmq/enabled_plugins # RabbitMQ 启用插件路径 networks: - 后端服务 makeline-service: build: src/makeline-service container_name: 'makeline-service' restart: always ports: - 3001:3001 healthcheck: test: ["CMD", "wget", "-O", "/dev/null", "-q", "http://makeline-service:3001/health"] # 检查 makeline-service 是否存活 interval: 30s timeout: 10s retries: 5 environment: - ORDER_QUEUE_URI=amqp://rabbitmq:5672 # 订单队列 URI - ORDER_QUEUE_USERNAME=username # 订单队列用户名 - ORDER_QUEUE_PASSWORD=password # 订单队列密码 - ORDER_QUEUE_NAME=orders # 订单队列名称 - ORDER_DB_URI=mongodb://mongodb:27017 # 订单数据库 URI - ORDER_DB_NAME=orderdb # 订单数据库名称 - ORDER_DB_COLLECTION_NAME=orders # 订单数据库集合名称 networks: - 后端服务 depends_on: rabbitmq: condition: 服务健康 # 取决于 RabbitMQ 服务健康状态 mongodb: condition: 服务健康 # 取决于 MongoDB 服务健康状态
真酷,作为一名开发者,我可以使用 docker compose
在本地运行 makeline-service
的容器及其依赖项,真好!
但是,开发人员在这种情况下面临的负担和认知压力是这样的:
他们应该了解 Docker Compose 的语法、网络等方面的知识;
他们应该维护 Docker Compose 文件;
他们应该知道如何在本地运行 mongodb
和 rabbitmq
容器;
他们应该手动将连接到 mongodb
和 rabbitmq
数据库的信息注入工作负载的环境变量中。这些值在两个地方是硬编码的。
mongodb
或 rabbitmq
,是否也需要了解或学习相关的知识呢?再次提到,Docker Compose 非常有帮助,但正如我们所观察到的,开发人员需要做的事情和要了解的知识还很多,这影响了他们将高质量的代码和功能提供给最终用户。
让我们现在看看这些示例应用程序如何在 Kubernetes 上部署。
要使用 Kubernetes 部署这些示例应用程序,你可以查看此教程或另一个教程。
此 Microsoft Azure 文档中的教程 或 另一个教程。
你可以找到这些文件,也可以找到这些工具,包括纯 Kubernetes 清单文件,Helm 图表 或者 Kustomize 资源。非常方便,有三种流行的方式来部署容器化工作负载到 Kubernetes。这说明学习起来非常方便。
我们来关注一下makeline-service
,及其两个依赖rabbitmq
和mongodb
:
apiVersion: v1 data: rabbitmq_enabled_plugins: | [rabbitmq_management,rabbitmq_prometheus,rabbitmq_amqp1_0]. kind: ConfigMap metadata: name: rabbitmq-enabled-plugins --- apiVersion: apps/v1 kind: StatefulSet metadata: name: rabbitmq spec: serviceName: rabbitmq replicas: 1 selector: matchLabels: app: rabbitmq template: metadata: labels: app: rabbitmq spec: nodeSelector: "kubernetes.io/os": linux containers: - name: rabbitmq image: mcr.microsoft.com/mirror/docker/library/rabbitmq:3.10-management-alpine ports: - containerPort: 5672 name: rabbitmq-amqp - containerPort: 15672 name: rabbitmq-http env: - name: RABBITMQ_DEFAULT_USER value: "username" - name: RABBITMQ_DEFAULT_PASS value: "password" resources: requests: cpu: 10m memory: 128Mi limits: cpu: 250m memory: 256Mi volumeMounts: - name: rabbitmq-enabled-plugins mountPath: /etc/rabbitmq/enabled_plugins subPath: enabled_plugins volumes: - name: rabbitmq-enabled-plugins configMap: name: rabbitmq-enabled-plugins items: - key: rabbitmq_enabled_plugins path: enabled_plugins --- apiVersion: v1 kind: Service metadata: name: rabbitmq spec: selector: app: rabbitmq ports: - name: rabbitmq-amqp port: 5672 targetPort: 5672 - name: rabbitmq-http port: 15672 targetPort: 15672 type: ClusterIP --- apiVersion: apps/v1 kind: StatefulSet metadata: name: mongodb spec: serviceName: mongodb replicas: 1 selector: matchLabels: app: mongodb template: metadata: labels: app: mongodb spec: nodeSelector: "kubernetes.io/os": linux containers: - name: mongodb image: mcr.microsoft.com/mirror/docker/library/mongo:4.2 ports: - containerPort: 27017 name: mongodb resources: requests: cpu: 5m memory: 75Mi limits: cpu: 25m memory: 1024Mi livenessProbe: exec: command: - mongosh - --eval - db.runCommand('ping').ok initialDelaySeconds: 5 periodSeconds: 5 --- apiVersion: v1 kind: Service metadata: name: mongodb spec: ports: - port: 27017 selector: app: mongodb type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: makeline-service spec: replicas: 1 selector: matchLabels: app: makeline-service template: metadata: labels: app: makeline-service spec: nodeSelector: "kubernetes.io/os": linux containers: - name: makeline-service image: ghcr.io/azure-samples/aks-store-demo/makeline-service:latest ports: - containerPort: 3001 env: - name: ORDER_QUEUE_URI value: "amqp://rabbitmq:5672" - name: ORDER_QUEUE_USERNAME value: "username" - name: ORDER_QUEUE_PASSWORD value: "password" - name: ORDER_QUEUE_NAME value: "orders" - name: ORDER_DB_URI value: "mongodb://mongodb:27017" - name: ORDER_DB_NAME value: "orderdb" - name: ORDER_DB_COLLECTION_NAME value: "orders" resources: requests: cpu: 1m memory: 6Mi limits: cpu: 5m memory: 20Mi startupProbe: httpGet: path: /health port: 3001 failureThreshold: 10 periodSeconds: 5 readinessProbe: httpGet: path: /health port: 3001 failureThreshold: 3 initialDelaySeconds: 3 periodSeconds: 5 livenessProbe: httpGet: path: /health port: 3001 failureThreshold: 5 initialDelaySeconds: 3 periodSeconds: 3 --- apiVersion: v1 kind: Service metadata: name: makeline-service spec: type: ClusterIP ports: - name: http port: 3001 targetPort: 3001 selector: app: makeline-service
就算比 Docker Compose 稍微麻烦一点点,我就能轻松部署应用到 Kubernetes,这也太牛了!
但这里有对开发人员的认知负担来说。
mongodb
和 rabbitmq
容器;mongodb
和 rabbitmq
数据库的信息注入工作负载的环境变量中。这些值在这两个地方被硬编码。mongodb
或 rabbitmq
,是否也需要了解这些?Deployment
上设置 securityContext
,注入 Istio 边车代理标签,添加成本中心标签和可观测性标签等),他们也需要了解吗?这里就要介绍Score,一个CNCF沙盒项目,能够帮助开发人员更简单地描述如何部署他们的容器化工作负载。开发人员需要为每个工作负载创建一个独立于环境和平台的Score文件。各种Score实现(如score-compose
,score-k8s
等)会自动生成相关技术细节和基础设施依赖。最后,开发人员可以用docker compose
或kubectl
来部署生成的文件。
展示代码!没错,确实,让我们用我们之前提到的 makeline-service
及其 rabbitmq
和 mongodb
依赖为例,开发者会这样定义 Score 文件(如下面所示):
apiVersion: score.dev/v1b1 # API版本,用于指定配置文件的版本 metadata: name: makeline-service containers: makeline-service: image: ghcr.io/azure-samples/aks-store-demo/makeline-service:1.5.1 variables: ORDER_QUEUE_URI: "amqp://${resources.orders-queue.host}:${resources.orders-queue.port}" # 订单队列的AMQP URI ORDER_QUEUE_USERNAME: "${resources.orders-queue.username}" ORDER_QUEUE_PASSWORD: "${resources.orders-queue.password}" ORDER_QUEUE_NAME: "orders" ORDER_DB_URI: "${resources.orders-database.connection}" # 订单数据库的连接URI ORDER_DB_NAME: "orderdb" ORDER_DB_COLLECTION_NAME: "orders" livenessProbe: httpGet: path: /health, # 健康检查路径 port: 3001, # 健康检查端口 readinessProbe: httpGet: path: /health, # 健康检查路径 port: 3001, # 健康检查端口 resources: limits: memory: "20Mi" # 内存限制 cpu: "5m" # CPU限制 requests: memory: "6Mi" # 内存请求 cpu: "1m" # CPU请求 service: ports: http: port: 3001 targetPort: 3001 resources: orders-queue: type: amqp id: orders-queue orders-database: type: mongodb
开发人员不需要为了针对多个平台或环境而写多个文件,这个 Score 文件保持不变。相关的 Score 实现及其提供程序会处理这些问题,让开发人员无需关心。之前提到的与 Docker compose 文件和 Kubernetes 配置文件相关的大部分甚至所有负担和认知负荷已经被移除或简化了。开发人员不再需要担心在 Docker Compose 或 Kubernetes 中配置 mongodb
或 rabbitmq
的依赖项,他们也不需要重复硬编码的信息来连接到这些服务。
真酷,对吧?!
在这里可以找到所有工作负载的Score文件所在位置,如果你想了解更多,可以查看更多例子。
来展示一下魔法吧!当然,咱们来看看下面这两个 Score 实现的实例:score-compose
和 score-k8s
(如下所示)。
现在,让我们通过 score-compose
来部署配置文件,使用 Docker Compose。
首先,我们需要设置本地的 score-compose
工作区:
score-compose init
这将启用 score-compose
的默认提供程序。你可以在这里找到这些默认提供程序的实现代码。默认支持 mongodb
、amqp
(即 rabbitmq
)、mysql
、postgres
、redis
、s3
(即 minio
)等。你也可以自定义这些提供程序,实际上,平台工程师会为开发人员提供这些自定义的提供程序。
其次,我们需要根据Score文件(或得分文件)来创建Docker Compose文件。
使用 score-compose 命令生成如下文件:
apps/order/score.yaml apps/product/score.yaml apps/store-front/score.yaml apps/store-admin/score.yaml apps/makeline/score.yaml
最后,运行这个生成的 compose.yaml
。
执行此命令来构建并启动Docker容器,如果有需要的话: docker compose up --build -d
就这样,你根本不需要去了解或学习Docker Compose(确实,你需要在你的机器上安装Docker和Docker Compose工具)。
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES aa94154f047c ghcr.io/azure-samples/aks-store-demo/product-service:1.5.1 "./product-service" 38 seconds ago Up 14 seconds aks-store-demo-product-service-product-service-1 51f3b0de2a48 ghcr.io/azure-samples/aks-store-demo/makeline-service:1.5.1 "./main" 38 seconds ago Up 14 seconds 3001/tcp aks-store-demo-makeline-service-makeline-service-1 b608ed30d6fa ghcr.io/azure-samples/aks-store-demo/order-service:1.5.1 "docker-entrypoint.s…" 38 seconds ago Up 15 seconds 3000/tcp aks-store-demo-order-service-order-service-1 f6eb76c47f27 ghcr.io/azure-samples/aks-store-demo/store-admin:1.5.1 "/docker-entrypoint.…" 38 seconds ago Up 15 seconds 80/tcp, 8081/tcp aks-store-demo-store-admin-store-admin-1 ec852c04d166 ghcr.io/azure-samples/aks-store-demo/store-front:1.5.1 "/docker-entrypoint.…" 38 seconds ago Up 14 seconds 80/tcp, 8080/tcp aks-store-demo-store-front-store-front-1 ed39a9b5a354 mongo:7 "docker-entrypoint.s…" 39 seconds ago Up 37 seconds (healthy) 27017/tcp aks-store-demo-mongo-ENMnhn-1 6e4197ba7784 rabbitmq:3-management-alpine "docker-entrypoint.s…" 39 seconds ago Up 36 seconds (healthy) 4369/tcp, 5671-5672/tcp, 15671-15672/tcp, 15691-15692/tcp, 25672/tcp aks-store-demo-rabbitmq-RdWyvb-1 a7a590866b63 nginx:1 "/docker-entrypoint.…" 39 seconds ago Up 36 seconds 0.0.0.0:8080->80/tcp, :::8080->80/tcp aks-store-demo-routing-CWlOTJ-1
现在,我们通过 score-k8s
部署这些 Score 文件到 Kubernetes 上。
首先,我们需要设置初始化本地 score-k8s
工作区。
score-k8s 运行初始化脚本
这将启用默认的 score-k8s
提供器。你可以在这里找到这些默认提供器的具体实现(这里):默认支持 mongodb
、amqp
(即 rabbitmq
)、mysql
、postgres
、redis
等。你也可以使用自己的提供器,实际上,平台工程师会为开发人员提供这些提供器。
其次,我们需要基于Score文件,生成Kubernetes清单文件。
score-k8s 生成如下配置文件 \ apps/makeline/score.yaml \ apps/order/score.yaml \ apps/product/score.yaml \ apps/store-admin/score.yaml \ apps/store-front/score.yaml
最后,你通过如下命令使用 kubectl
推送生成的 manifests.yaml
文件。
kubectl apply -f manifests.yaml
运行这个命令来应用 manifests.yaml
文件中的配置。
就这样,你不需要了解或学习任何关于Kubernetes的知识,不过你需要访问Kubernetes集群,并且已经在你的机器上安装了kubectl
。
$ kubectl get all,secrets NAME 就绪 状态 重启次数 运行时间 pod/makeline-service-6dbbd7d87c-zv6bw 1/1 Running 1 (61s ago) 2m1s pod/mongo-makeline-service-f587824d-0 1/1 Running 0 2m1s pod/order-service-964c5d745-rqzff 1/1 Running 0 2m1s pod/product-service-69748fc7cd-hfbwc 1/1 Running 0 2m1s pod/rabbitmq-order-service-536fdcc5-0 1/1 Running 0 2m1s pod/store-admin-957f48c68-fzvhp 1/1 Running 0 2m pod/store-front-68fcdbbd4b-2d4d4 1/1 Running 0 2m NAME 类型 CLUSTER-IP EXTERNAL-IP PORT(S) 运行时间 service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2m54s service/makeline-service ClusterIP 10.96.233.39 <none> 3001/TCP 2m1s service/mongo-makeline-service-f587824d ClusterIP 10.96.132.140 <none> 27017/TCP 2m1s service/order-service ClusterIP 10.96.133.185 <none> 3000/TCP 2m1s service/product-service ClusterIP 10.96.187.196 <none> 3002/TCP 2m1s service/rabbitmq-order-service-536fdcc5 ClusterIP 10.96.185.130 <none> 5672/TCP,15672/TCP 2m1s service/store-admin ClusterIP 10.96.11.168 <none> 8081/TCP 2m1s service/store-front ClusterIP 10.96.33.231 <none> 8080/TCP 2m NAME 就绪 最新 可用 运行时间 deployment.apps/makeline-service 1/1 1 1 2m1s deployment.apps/order-service 1/1 1 1 2m1s deployment.apps/product-service 1/1 1 1 2m1s deployment.apps/store-admin 1/1 1 1 2m1s deployment.apps/store-front 1/1 1 1 2m NAME 期望 当前 就绪 运行时间 replicaset.apps/makeline-service-6dbbd7d87c 1 1 1 2m1s replicaset.apps/order-service-964c5d745 1 1 1 2m1s replicaset.apps/product-service-69748fc7cd 1 1 1 2m1s replicaset.apps/store-admin-957f48c68 1 1 1 2m1s replicaset.apps/store-front-68fcdbbd4b 1 1 1 2m NAME 就绪 运行时间 statefulset.apps/mongo-makeline-service-f587824d 1/1 2m1s statefulset.apps/rabbitmq-order-service-536fdcc5 1/1 2m1s NAME 类型 数据量 运行时间 secret/mongo-makeline-service-f587824d Opaque 1 2m1s secret/rabbitmq-order-service-536fdcc5-secret Opaque 3 2m1s
所以,开发人员只需要专注于给自己的客户提供价值,他们不需要直接处理Kubernetes或云基础设施等。Score的存在是为了让平台工程师能够提供并展示他们自己的Score实现和提供者。这都是为了实现高效且无缝的协作和抽象化,在大规模环境中运行。score-compose
和 score-k8s
是两个默认、非常流行和强大的Score实现。
等不及想要看看CNCF社区会将这个Score项目及其项目默认实现和提供程序提升到下一个层次!真是太激动人心了!