K8s 源码阅读7
In this chapter we’ll discuss the operational aspects of controllers and operators, showing you how to package them, walking you through best practices for running controllers in production, and making sure that your extension points don’t break your Kubernetes cluster, security, or performance-wise.
Lifecycle Management and Packaging
Let’s start with the low-hanging fruit: packaging and delivering your controllers so that a user can install it in a straightforward manner.
Packaging: The Challenge
While Kubernetes defines resources with manifest, typically written in YAML, a low-level interface to declare the state of resources, these manifest files have shortcoming. Most importantly in the context of packaging containerized apps, the YAML manifests are static; that is, all values in a YAML manifest are fixed. This means that if you want to change the container images in a deployment manifest, for example, you have to create a new manifest.
Let’s look a concrete example, Assume you have the following Kubernetes deployment encoded in a YAML manifest called mycontroller.yaml
, representing the custom controller you’d like user to install:
1apiVersion: apps/v1beta1
2kind: Deployment
3metadata:
4 name: mycustomcontroller
5spec:
6 replicas: 1
7 template:
8 metadata:
9 labels:
10 app: customcontroller
11 spec:
12 containers:
13 - name: thecontroller
14 images: example/controller:0.1.0
15 ports:
16 - containerPort: 9999
17 env:
18 - name: REGION
19 value: eu-west-1
Imagine the environment variable REGION defines certain runtime properties of you controller, such as the availability of other service like a managed service mesh. In other words, while the default values eu-west-1
might be a sensible one, users can and likely will overwrite it, based on their own preferences or policies.
Now, given that the YAML manifest mycontroller.yaml
itself is a static file with all values defined at the time of writing – and clients such as kubectl
don’t inherently support variable parts in the manifest – how do you enable users to supply variable values or overwrite existing values at runtime? That is, how in the preceding example can a user set REGION to, say, us-east-2 when they’re installing it, using (for example) kubeclt apply?
To overcome these limitations of build-time, static YAML manifest in Kubernetes, there are a few options to templatize the manifest (Helm, for example) or otherwise enable variable input (Kustomize), depending on user-provided values or runtime properties.
Helm
Helm, which touts itself as the package manager for Kubernetes, was originally developed by Deis and is now a Cloud Native Computing Foundation(CNCF) project with major contributors form Microsoft, Google, and Bitnami(now pat of VMware).
Helm helps you to install and upgrade Kubernetes applications by defining and applying so-called charts, effectively parameterized YAML manifests. Here is an excerpt of an example chart template.
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4 name: {{ include "flagger.fullname" .}}
5...
6spec:
7 replicas: 1
8 strategy:
9 type: Recreate
10 selector:
11 matchLabels:
12 app.kubernetes.io/name: {{ template "flagger.name" .}}
13 app.kubernetes.io/instance: {{ .Release.Name }}
14 template:
15 metadata:
16 labels:
17 app.kubernetes.io/name: {{ template "flagger.name" .}}
18 app.kubernetes.io/instance: {{ .Release.Name }}
19 sepc:
20 serviceAccountName: {{ template "flagger.serviceAccountName" .}}
21 containers:
22 - name: flagger
23 securityContext:
24 readOnlyRootFileSystem: true
25 runAsUser: 10001
26 image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
27
As you can see, variables are encoded in {{ ._Some.value.here_ }}
format, which happens to be Go templates.
To install a chart, you can run the helm install
command. While Helm has several ways to find and install charts, the easiest is to use on of the official stable charts:
1# get the latest list of charts
2helm repo update
3
4# install MySQL
5helm install stable/mysql
6
7# list running apps
8helm ls
9
10# remove it
11helm delete <helm name>
In order to package you controller, you will need to create a Helm Chart for it and publish it somewhere, by default to a public repository indexed and accessible through the Helm hub.
Helm is popular, partly because of it ease of use for end users. However, some argue the current Helm architecture introduces security risks. The good news is that the community is actively working on addressing those.