在现代软件开发和交付中,确保应用程序的平稳更新和发布对于用户体验和业务连续性至关重要。蓝绿部署是一种备受推崇的部署策略,它允许开发团队在不影响用户的情况下,将新版本的应用程序引入生产环境。
蓝绿部署的核心思想在于维护两个独立的环境:蓝环境和绿环境。蓝环境是当前正在运行的稳定版本,而绿环境是即将发布的新版本。在进行部署时,首先将新版本部署到绿环境中,并在绿环境中进行严格的测试和验证。一旦新版本通过了各项测试,并被确认为稳定和可靠,就可以将流量从蓝环境切换到绿环境,使用户开始访问新版本。
考虑一个在线购物应用,用户可以浏览商品、添加到购物车并完成购买。为了演示蓝绿部署,我们假设当前应用的版本为1.0(蓝环境),而开发团队已经开发了一个新版本2.0(绿环境),其中包含了一些界面改进和性能优化。
以下是蓝绿部署的步骤:
云原生的浪潮下, 越来越多的团队都将应用迁移到了Kubernetes的环境中, Kubernetes使应用的部署变得方便快捷,但Kubernetes却并未原生提供蓝绿部署的功能。它提供了Deployment对象,可以实现“滚动更新”(RollingUpdate)。这使得可以在应用程序更新时实现零停机时间,通过逐步用新版本的应用程序替换Pod。
虽然这类似于蓝绿部署,但并未提供其所有的好处。比如在滚动部署中,如果新版本出现问题,回滚可能到旧版本需要重新部署应用,这就需要更多的时间,而不能像蓝绿部署一样,可以即时切换新旧版本, 从而最大限度的保障系统的可用性。
虽然Kubernetes没有提供原生的蓝绿部署功能,但丰富的自定义资源往往可以帮我们在Kubernetes的世界中实现各种各样美好的愿望。Argo的Rollouts就是一个比较流行好用的工具。Argo Rollouts安装指南
Argo Rollouts是一个运行在Kubernetes中的渐进式发布控制器,它支持多种部署策略,其中包括蓝绿部署和金丝雀部署。Argo Rollouts提供了一个名为Rollout的新的Kubernetes资源类型,类似于Deployment,用户可以通过指定额外的参数,从而设置高级的部署策略。
下面是Rollout自动执行蓝绿部署的方式:
通过这种方式,Rollout对象实现了自动的蓝绿部署,使得应用程序的更新能够在不影响用户使用的情况下进行。这为团队提供了更灵活、可控的部署流程,同时最大程度地减少了潜在的风险。
如下是一份配置蓝绿部署策略的Rollout资源配置示例:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: rollout-bluegreen
spec:
[...] # 省略的配置的格式与Deployment的配置格式完全相同
strategy:
blueGreen:
activeService: service-active
previewService: service-preview
autoPromotionEnabled: false
kubectl argo rollouts promote
手动进行版本切换。如果设置为true,默认情况下,当新版本Pod Ready时,Rollout会立即切换活跃版本到新版本pod。值得注意的是,上述配置中的activeService和previewService这两项指定的服务不会被自动创建,而需要根据Rollout的配置手动创建,以上面的Rollout的示例配置为基础,应当创建两个Service,例如:
---
apiVersion: v1
kind: Service
metadata:
name: service-active
spec:
selector:
app: your-app-label
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
name: service-preview
spec:
selector:
app: your-app-label
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP
一个服务的行为不仅取决于源代码,也与其运行时的配置相关, 在kubernetes中,配置通常通过Configmap来生成,例如下面的配置:
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-app
spec:
replicas: 1
revisionHistoryLimit: 2
selector:
matchLabels:
app: demo-configmap
template:
metadata:
labels:
app: demo-configmap
spec:
containers:
- name: demo-container
image: demo-app:latest
env:
- name: DB_USER
valueFrom:
configMapKeyRef:
name: demo-settings
key: DB_USER
- name: DB_URL
valueFrom:
configMapKeyRef:
name: demo-settings
key: DB_URL
[...snip...]
---
apiVersion: v1
kind: ConfigMap
metadata:
name: demo-settings
data:
DB_URL: "10.1.1.1:3306"
DB_USER: "myuser"
上面的配置中, 在容器运行时会从demo-settings
这个Configmap中获取对应的值作为环境变量,分别是:
DB_URL: "10.1.1.1:3306"
DB_USER: "myuser"
此时,我们希望将应用连接到另一个数据库(使用不同的url和用户)进行测试,例如:
DB_URL: "10.1.1.2:3306"
DB_USER: "testuser"
为了使环境中同时存在使用两个不同数据库的服务,我们需要一种方式来同时保持两个 ConfigMap的存在,并且每个都具有其相应的配置。这可以通过使用 ConfigMap Generator
来实现, 这是一个与 Argo Rollouts 无关的功能,它是 Kustomize 的内置功能,可以用于标准的滚动部署,我们也可以利用它进行渐进式交付。
Configmap Generator
的工作原理如下:kustomize会根据Configmap Generator
中配置的name
, 动态的创建一个ConfigMap, 创建的这个ConfigMap的名称是name
的值加上一个唯一的后缀, 例如:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yml
- service.yml
# declare ConfigMap from a ConfigMapGenerator
configMapGenerator:
- name: demo-settings
literals:
- DB_URL="10.1.1.2:3306"
- DB_USER="testuser"
这时我们查看deployment
的yaml内容, 其中使用了这个动态生成的ConfigMap:
[...snip...]
spec:
containers:
- env:
- name: DB_URL
- valueFrom:
configMapKeyRef:
key: DB_URL
name: demo-settings-2k9m722878
- name: DB_USER
valueFrom:
configMapKeyRef:
key: DB_USER
name: demo-settings-2k9m722878
[...snip...]
查看这个动态的ConfigMap的内容:
apiVersion: v1
name: demo-settings-2km722878
data:
DB_URL: "10.1.1.2:3306"
DB_USER: "testuser"
在上一小节中,我们已经知道了Configmap Generator的工作原理,在Argo Rollout中合理的利用它的特性,就可以实现配置的蓝绿部署和渐进式发布。首先,我们将上文中的Deployment清单转换成Rollout清单:
# example-rollout.yml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: demo-app
spec:
replicas: 3
strategy:
blueGreen:
activeService: configmaps-example-active
previewService: configmaps-example-preview
autoPromotionEnabled: false
revisionHistoryLimit: 2
selector:
matchLabels:
app: demo-configmap
template:
metadata:
labels:
app: demo-configmap
spec:
containers:
- name: my-container
image: demo-app:latest
env:
- name: DB_URL
valueFrom:
configMapKeyRef:
name: demo-settings
key: DB_URL
- name: DB_USER
valueFrom:
configMapKeyRef:
name: demo-settings
key: DB_USER
[...snip...]
然后修改我们的kustomization清单:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# declare ConfigMap as a resource
resources:
- example-rollout.yml
- service-active.yml
- service-preview.yml
configurations:
- https://argoproj.github.io/argo-rollouts/features/kustomize/rollout-transform.yaml
注意:
configuration
这一行不可省略,其作用是启用kustomization的rollout功能,由于Argo Rollout不是原生的Kubernetes资源,因此必须通过yaml来告知kustomization, Rollout资源的详细信息。首先对应用进行首次部署
kustomize build . | kubectl apply -f -
kubectl-argo-rollouts get rollout demo-app
结果如下:
Name: demo-app
Namespace: default
Status: ~ Healthy
Strategy: BlueGreen
Images: demo-app:latest (stable, active)
Replicas:
Desired: 3
Current: 3
Updated: 3
Ready: 3
Available: 3
NAME KIND STATUS AGE INFO
~ demo-app Rollout Healthy 15s
└──# revision: 1
└── demo-app-55df5b623d ReplicaSet Healthy 15s stable,active
├── demo-app-55df5b623d-2nlgf Pod Healthy 15s ready:1/1
├── demo-app-55df5b623d-78udn Pod Healthy 15s ready:1/1
└── demo-app-55df5b623d-6sceo Pod Healthy 15s ready:1/1
现在我们来改变配置,在Configmap Generator中更改配置:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# declare ConfigMap as a resource
resources:
- example-rollout.yml
- service-active.yml
- service-preview.yml
configurations:
- https://argoproj.github.io/argo-rollouts/features/kustomize/rollout-transform.yaml
configMapGenerator:
- name: demo-settings
literals:
- DB_URL="10.1.1.2:3306"
- DB_USER="testuser"
运行命令进行蓝绿部署并查看结果:
kustomize build . | kubectl apply -f -
kubectl-argo-rollouts get rollout demo-app
结果如下:
Name: demo-app
Namespace: default
Status: Paused
Message: BlueGreenPause
Strategy: BlueGreen
Images: demo-app:latest (active, preview, stable)
Replicas:
Desired: 3
Current: 6
Updated: 3
Ready: 3
Available: 3
NAME KIND STATUS AGE INFO
~ demo-app Rollout Paused 100s
├──# revision: 2
│ └── demo-app-76tk9i812c ReplicaSet Healthy 10s preview
│ ├── demo-app-76tk9i812c-1nvlf Pod Healthy 10s ready:1/1
│ ├── demo-app-76tk9i812c-70qce Pod Healthy 10s ready:1/1
│ └── demo-app-76tk9i812c-21kap Pod Healthy 10s ready:1/1
└──# revision: 1
└── demo-app-55df5b623d ReplicaSet Healthy 100s stable,active
├── demo-app-55df5b623d-2nlgf Pod Healthy 100s ready:1/1
├── demo-app-55df5b623d-78udn Pod Healthy 100s ready:1/1
└── demo-app-55df5b623d-6sceo Pod Healthy 100s ready:1/1
进入对应的Pod中查看环境变量,可以看到已经生效,检验成功。
通过上面的方法,我们可以仅使用 Argo Rollouts 进行配置更改,在不修改容器镜像的情况下,只需更改配置即可执行蓝/绿部署和金丝雀部署。如果你想要在生产 Kubernetes 集群中微调应用程序配置参数,而不想使用新的容器镜像,那么希望这篇文章将会给你一些启发和帮助。