update zookeeper tutorial for 1.8 release

This commit is contained in:
Kenneth Owens
2017-09-15 14:26:19 -07:00
committed by Andrew Chen
parent daac519af8
commit 532c60d3c3
3 changed files with 160 additions and 249 deletions
+103 -169
View File
@@ -27,7 +27,6 @@ Kubernetes concepts.
* [Headless Services](/docs/concepts/services-networking/service/#headless-services) * [Headless Services](/docs/concepts/services-networking/service/#headless-services)
* [PersistentVolumes](/docs/concepts/storage/volumes/) * [PersistentVolumes](/docs/concepts/storage/volumes/)
* [PersistentVolume Provisioning](https://github.com/kubernetes/examples/tree/{{page.githubbranch}}/staging/persistent-volume-provisioning/) * [PersistentVolume Provisioning](https://github.com/kubernetes/examples/tree/{{page.githubbranch}}/staging/persistent-volume-provisioning/)
* [ConfigMaps](/docs/tasks/configure-pod-container/configmap/)
* [StatefulSets](/docs/concepts/abstractions/controllers/statefulsets/) * [StatefulSets](/docs/concepts/abstractions/controllers/statefulsets/)
* [PodDisruptionBudgets](/docs/admin/disruptions/#specifying-a-poddisruptionbudget) * [PodDisruptionBudgets](/docs/admin/disruptions/#specifying-a-poddisruptionbudget)
* [PodAntiAffinity](/docs/user-guide/node-selection/#inter-pod-affinity-and-anti-affinity-beta-feature) * [PodAntiAffinity](/docs/user-guide/node-selection/#inter-pod-affinity-and-anti-affinity-beta-feature)
@@ -90,27 +89,27 @@ safely discarded.
The manifest below contains a The manifest below contains a
[Headless Service](/docs/user-guide/services/#headless-services), [Headless Service](/docs/user-guide/services/#headless-services),
a [ConfigMap](/docs/tasks/configure-pod-container/configmap/), a [Service](/docs/concepts/services-networking/service),
a [PodDisruptionBudget](/docs/admin/disruptions/#specifying-a-poddisruptionbudget), a [PodDisruptionBudget](/docs/admin/disruptions/#specifying-a-poddisruptionbudget),
and a [StatefulSet](/docs/concepts/abstractions/controllers/statefulsets/). and a [StatefulSet](/docs/concepts/abstractions/controllers/statefulsets/).
{% include code.html language="yaml" file="zookeeper.yaml" ghlink="/docs/tutorials/stateful-application/zookeeper.yaml" %} {% include code.html language="yaml" file="zookeeper.yaml" ghlink="/docs/tutorials/stateful-application/zookeeper.yaml" %}
Open a command terminal, and use Open a command terminal, and use
[`kubectl create`](/docs/user-guide/kubectl/{{page.version}}/#create) to create the [`kubectl apply`](/docs/user-guide/kubectl/{{page.version}}/#apply) to create the
manifest. manifest.
```shell ```shell
kubectl create -f https://k8s.io/docs/tutorials/stateful-application/zookeeper.yaml kubectl apply -f https://k8s.io/docs/tutorials/stateful-application/zookeeper.yaml
``` ```
This creates the `zk-headless` Headless Service, the `zk-config` ConfigMap, This creates the `zk-hs` Headless Service, the `zk-cs` Service,
the `zk-budget` PodDisruptionBudget, and the `zk` StatefulSet. the `zk-pdb` PodDisruptionBudget, and the `zk` StatefulSet.
```shell ```shell
service "zk-headless" created service "zk-hs" created
configmap "zk-config" created service "zk-cs" created
poddisruptionbudget "zk-budget" created poddisruptionbudget "zk-pdb" created
statefulset "zk" created statefulset "zk" created
``` ```
@@ -200,13 +199,13 @@ Get the FQDN (Fully Qualified Domain Name) of each Pod in the `zk` StatefulSet.
for i in 0 1 2; do kubectl exec zk-$i -- hostname -f; done for i in 0 1 2; do kubectl exec zk-$i -- hostname -f; done
``` ```
The `zk-headless` Service creates a domain for all of the Pods, The `zk-hs` Service creates a domain for all of the Pods,
`zk-headless.default.svc.cluster.local`. `zk-headless.default.svc.cluster.local`.
```shell ```shell
zk-0.zk-headless.default.svc.cluster.local zk-0.zk-hs.default.svc.cluster.local
zk-1.zk-headless.default.svc.cluster.local zk-1.zk-hs.default.svc.cluster.local
zk-2.zk-headless.default.svc.cluster.local zk-2.zk-hs.default.svc.cluster.local
``` ```
The A records in [Kubernetes DNS](/docs/concepts/services-networking/dns-pod-service/) resolve the FQDNs to the Pods' IP addresses. The A records in [Kubernetes DNS](/docs/concepts/services-networking/dns-pod-service/) resolve the FQDNs to the Pods' IP addresses.
@@ -251,10 +250,6 @@ which processes have committed which data. If two Pods were launched with the
same ordinal, two ZooKeeper servers would both identify themselves as the same same ordinal, two ZooKeeper servers would both identify themselves as the same
server. server.
When you created the `zk` StatefulSet, the StatefulSet's controller created
each Pod sequentially, in the order defined by the Pods' ordinal indices, and it
waited for each Pod to be Running and Ready before creating the next Pod.
```shell ```shell
kubectl get pods -w -l app=zk kubectl get pods -w -l app=zk
NAME READY STATUS RESTARTS AGE NAME READY STATUS RESTARTS AGE
@@ -281,18 +276,18 @@ endpoint will be the unique ZooKeeper server claiming the identity configured
in its `myid` file. in its `myid` file.
```shell ```shell
zk-0.zk-headless.default.svc.cluster.local zk-0.zk-hs.default.svc.cluster.local
zk-1.zk-headless.default.svc.cluster.local zk-1.zk-hs.default.svc.cluster.local
zk-2.zk-headless.default.svc.cluster.local zk-2.zk-hs.default.svc.cluster.local
``` ```
This ensures that the `servers` properties in the ZooKeepers' `zoo.cfg` files This ensures that the `servers` properties in the ZooKeepers' `zoo.cfg` files
represents a correctly configured ensemble. represents a correctly configured ensemble.
```shell ```shell
server.1=zk-0.zk-headless.default.svc.cluster.local:2888:3888 server.1=zk-0.zk-hs.default.svc.cluster.local:2888:3888
server.2=zk-1.zk-headless.default.svc.cluster.local:2888:3888 server.2=zk-1.zk-hs.default.svc.cluster.local:2888:3888
server.3=zk-2.zk-headless.default.svc.cluster.local:2888:3888 server.3=zk-2.zk-hsdefault.svc.cluster.local:2888:3888
``` ```
When the servers use the Zab protocol to attempt to commit a value, they will When the servers use the Zab protocol to attempt to commit a value, they will
@@ -395,13 +390,6 @@ kubectl apply -f https://k8s.io/docs/tutorials/stateful-application/zookeeper.ya
The `zk` StatefulSet will be created, but, as they already exist, the other API The `zk` StatefulSet will be created, but, as they already exist, the other API
Objects in the manifest will not be modified. Objects in the manifest will not be modified.
```shell
statefulset "zk" created
Error from server (AlreadyExists): error when creating "zookeeper.yaml": services "zk-headless" already exists
Error from server (AlreadyExists): error when creating "zookeeper.yaml": configmaps "zk-config" already exists
Error from server (AlreadyExists): error when creating "zookeeper.yaml": poddisruptionbudgets.policy "zk-budget" already exists
```
Watch the StatefulSet controller recreate the StatefulSet's Pods. Watch the StatefulSet controller recreate the StatefulSet's Pods.
```shell ```shell
@@ -513,143 +501,42 @@ As noted in the [Facilitating Leader Election](#facilitating-leader-election) an
[Achieving Consensus](#achieving-consensus) sections, the servers in a [Achieving Consensus](#achieving-consensus) sections, the servers in a
ZooKeeper ensemble require consistent configuration in order to elect a leader ZooKeeper ensemble require consistent configuration in order to elect a leader
and form a quorum. They also require consistent configuration of the Zab protocol and form a quorum. They also require consistent configuration of the Zab protocol
in order for the protocol to work correctly over a network. You can use in order for the protocol to work correctly over a network. In our example we
ConfigMaps to achieve this. achive consistent configuration by embedding the configuration directly into
the manifest.
Get the `zk-config` ConfigMap. Get the `zk` StatefulSet.
```shell ```shell{% raw %}
kubectl get cm zk-config -o yaml kubectl get sts zk -o yaml
apiVersion: v1 ...
data:
client.cnxns: "60"
ensemble: zk-0;zk-1;zk-2
init: "10"
jvm.heap: 2G
purge.interval: "0"
snap.retain: "3"
sync: "5"
tick: "2000"
```
The `env` field of the `zk` StatefulSet's Pod `template` reads the ConfigMap
into environment variables. These variables are injected into the containers
environment.
```yaml
env:
- name : ZK_ENSEMBLE
valueFrom:
configMapKeyRef:
name: zk-config
key: ensemble
- name : ZK_HEAP_SIZE
valueFrom:
configMapKeyRef:
name: zk-config
key: jvm.heap
- name : ZK_TICK_TIME
valueFrom:
configMapKeyRef:
name: zk-config
key: tick
- name : ZK_INIT_LIMIT
valueFrom:
configMapKeyRef:
name: zk-config
key: init
- name : ZK_SYNC_LIMIT
valueFrom:
configMapKeyRef:
name: zk-config
key: tick
- name : ZK_MAX_CLIENT_CNXNS
valueFrom:
configMapKeyRef:
name: zk-config
key: client.cnxns
- name: ZK_SNAP_RETAIN_COUNT
valueFrom:
configMapKeyRef:
name: zk-config
key: snap.retain
- name: ZK_PURGE_INTERVAL
valueFrom:
configMapKeyRef:
name: zk-config
key: purge.interval
```
The entry point of the container invokes a bash script, `zkGenConfig.sh`, prior to
launching the ZooKeeper server process. This bash script generates the
ZooKeeper configuration files from the supplied environment variables.
```yaml
command: command:
- sh - sh
- -c - -c
- zkGenConfig.sh && zkServer.sh start-foreground - "start-zookeeper \
``` --servers=3 \
--data_dir=/var/lib/zookeeper/data \
--data_log_dir=/var/lib/zookeeper/data/log \
--conf_dir=/opt/zookeeper/conf \
--client_port=2181 \
--election_port=3888 \
--server_port=2888 \
--tick_time=2000 \
--init_limit=10 \
--sync_limit=5 \
--heap=512M \
--max_client_cnxns=60 \
--snap_retain_count=3 \
--purge_interval=12 \
--max_session_timeout=40000 \
--min_session_timeout=4000 \
--log_level=INFO"
...
```{% endraw %}
Examine the environment of all of the Pods in the `zk` StatefulSet. Notice that the command used to start the ZooKeeper servers passed the configuration
as command line parameter. Enviornment variables are another, equally good, way to
```shell pass configuration to ensemble.
for i in 0 1 2; do kubectl exec zk-$i env | grep ZK_*;echo""; done
```
All of the variables populated from `zk-config` contain identical values. This
allows the `zkGenConfig.sh` script to create consistent configurations for all
of the ZooKeeper servers in the ensemble.
```shell
ZK_ENSEMBLE=zk-0;zk-1;zk-2
ZK_HEAP_SIZE=2G
ZK_TICK_TIME=2000
ZK_INIT_LIMIT=10
ZK_SYNC_LIMIT=2000
ZK_MAX_CLIENT_CNXNS=60
ZK_SNAP_RETAIN_COUNT=3
ZK_PURGE_INTERVAL=0
ZK_CLIENT_PORT=2181
ZK_SERVER_PORT=2888
ZK_ELECTION_PORT=3888
ZK_USER=zookeeper
ZK_DATA_DIR=/var/lib/zookeeper/data
ZK_DATA_LOG_DIR=/var/lib/zookeeper/log
ZK_LOG_DIR=/var/log/zookeeper
ZK_ENSEMBLE=zk-0;zk-1;zk-2
ZK_HEAP_SIZE=2G
ZK_TICK_TIME=2000
ZK_INIT_LIMIT=10
ZK_SYNC_LIMIT=2000
ZK_MAX_CLIENT_CNXNS=60
ZK_SNAP_RETAIN_COUNT=3
ZK_PURGE_INTERVAL=0
ZK_CLIENT_PORT=2181
ZK_SERVER_PORT=2888
ZK_ELECTION_PORT=3888
ZK_USER=zookeeper
ZK_DATA_DIR=/var/lib/zookeeper/data
ZK_DATA_LOG_DIR=/var/lib/zookeeper/log
ZK_LOG_DIR=/var/log/zookeeper
ZK_ENSEMBLE=zk-0;zk-1;zk-2
ZK_HEAP_SIZE=2G
ZK_TICK_TIME=2000
ZK_INIT_LIMIT=10
ZK_SYNC_LIMIT=2000
ZK_MAX_CLIENT_CNXNS=60
ZK_SNAP_RETAIN_COUNT=3
ZK_PURGE_INTERVAL=0
ZK_CLIENT_PORT=2181
ZK_SERVER_PORT=2888
ZK_ELECTION_PORT=3888
ZK_USER=zookeeper
ZK_DATA_DIR=/var/lib/zookeeper/data
ZK_DATA_LOG_DIR=/var/lib/zookeeper/log
ZK_LOG_DIR=/var/log/zookeeper
```
### Configuring Logging ### Configuring Logging
@@ -783,6 +670,54 @@ common pattern. When deploying an application in Kubernetes, rather than using
an external utility as a supervisory process, you should use Kubernetes as the an external utility as a supervisory process, you should use Kubernetes as the
watchdog for your application. watchdog for your application.
### Updating the Ensemble
The `zk` StatefulSet is configured to use the RollingUpdate update strategy.
You can use `kubectl patch` to update the number of `cpus` allocated to the servers.
```shell{% raw %}
kubectl patch sts zk --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/resources/requests/cpu", "value":"0.3"}]'
statefulset "zk" patched
```{% endraw %}
Use `kubectl rollout status` to watch the status of the update.
```shell
kubectl rollout status sts/zk
waiting for statefulset rolling update to complete 0 pods at revision zk-5db4499664...
Waiting for 1 pods to be ready...
Waiting for 1 pods to be ready...
waiting for statefulset rolling update to complete 1 pods at revision zk-5db4499664...
Waiting for 1 pods to be ready...
Waiting for 1 pods to be ready...
waiting for statefulset rolling update to complete 2 pods at revision zk-5db4499664...
Waiting for 1 pods to be ready...
Waiting for 1 pods to be ready...
statefulset rolling update complete 3 pods at revision zk-5db4499664...
```
The Pods are terminated, one at a time, in reverse ordinal order, and they
are recreated with the new configuration. This ensures that quorum is maintained
during a rolling update.
Use `kubectl rollout history` to view a history or previous configurations.
```shell
kubectl rollout history sts/zk
statefulsets "zk"
REVISION
1
2
```
Use `kubectl rollout undo` to roll back the modification.
```shell
kubectl rollout undo sts/zk
statefulset "zk" rolled back
```
### Handling Process Failure ### Handling Process Failure
@@ -1029,19 +964,18 @@ cordon all but four of the nodes in your cluster.
kubectl cordon < node name > kubectl cordon < node name >
```{% endraw %} ```{% endraw %}
Get the `zk-budget` PodDisruptionBudget. Get the `zk-pdb` PodDisruptionBudget.
```shell ```shell
kubectl get poddisruptionbudget zk-budget kubectl get pdb zk-pdb
``` ```
The `min-available` field indicates to Kubernetes that at least two Pods from The `max-unavailable` field indicates to Kubernetes that at most one Pod from
`zk` StatefulSet must be available at any time. `zk` StatefulSet can be unavailable at any time.
```yaml
NAME MIN-AVAILABLE ALLOWED-DISRUPTIONS AGE
zk-budget 2 1 1h
```shell
NAME MIN-AVAILABLE MAX-UNAVAILABLE ALLOWED-DISRUPTIONS AGE
zk-pdb N/A 1 1
``` ```
In one terminal, watch the Pods in the `zk` StatefulSet. In one terminal, watch the Pods in the `zk` StatefulSet.
@@ -1,9 +1,10 @@
---
apiVersion: v1 apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: zk-headless name: zk-hs
labels: labels:
app: zk-headless app: zk
spec: spec:
ports: ports:
- port: 2888 - port: 2888
@@ -15,43 +16,45 @@ spec:
app: zk app: zk
--- ---
apiVersion: v1 apiVersion: v1
kind: ConfigMap kind: Service
metadata: metadata:
name: zk-config name: zk-cs
data: labels:
ensemble: "zk-0;zk-1;zk-2" app: zk
jvm.heap: "2G" spec:
tick: "2000" ports:
init: "10" - port: 2181
sync: "5" name: client
client.cnxns: "60" selector:
snap.retain: "3" app: zk
purge.interval: "1"
--- ---
apiVersion: policy/v1beta1 apiVersion: policy/v1beta1
kind: PodDisruptionBudget kind: PodDisruptionBudget
metadata: metadata:
name: zk-budget name: zk-pdb
spec: spec:
selector: selector:
matchLabels: matchLabels:
app: zk app: zk
minAvailable: 2 maxUnavailable: 1
--- ---
apiVersion: apps/v1beta1 apiVersion: apps/v1beta2
kind: StatefulSet kind: StatefulSet
metadata: metadata:
name: zk name: zk
spec: spec:
serviceName: zk-headless selector:
matchLabels:
app: zk
serviceName: zk-hs
replicas: 3 replicas: 3
updateStrategy:
type: RollingUpdate
podManagementPolicy: Parallel
template: template:
metadata: metadata:
labels: labels:
app: zk app: zk
annotations:
pod.alpha.kubernetes.io/initialized: "true"
spec: spec:
affinity: affinity:
podAntiAffinity: podAntiAffinity:
@@ -61,16 +64,16 @@ spec:
- key: "app" - key: "app"
operator: In operator: In
values: values:
- zk-headless - zk
topologyKey: "kubernetes.io/hostname" topologyKey: "kubernetes.io/hostname"
containers: containers:
- name: k8szk - name: kubernetes-zookeeper
imagePullPolicy: Always imagePullPolicy: Always
image: gcr.io/google_samples/k8szk:v1 image: "gcr.io/google_containers/kubernetes-zookeeper:1.0-3.4.10"
resources: resources:
requests: requests:
memory: "4Gi" memory: "1Gi"
cpu: "1" cpu: "0.5"
ports: ports:
- containerPort: 2181 - containerPort: 2181
name: client name: client
@@ -78,68 +81,42 @@ spec:
name: server name: server
- containerPort: 3888 - containerPort: 3888
name: leader-election name: leader-election
env:
- name : ZK_ENSEMBLE
valueFrom:
configMapKeyRef:
name: zk-config
key: ensemble
- name : ZK_HEAP_SIZE
valueFrom:
configMapKeyRef:
name: zk-config
key: jvm.heap
- name : ZK_TICK_TIME
valueFrom:
configMapKeyRef:
name: zk-config
key: tick
- name : ZK_INIT_LIMIT
valueFrom:
configMapKeyRef:
name: zk-config
key: init
- name : ZK_SYNC_LIMIT
valueFrom:
configMapKeyRef:
name: zk-config
key: tick
- name : ZK_MAX_CLIENT_CNXNS
valueFrom:
configMapKeyRef:
name: zk-config
key: client.cnxns
- name: ZK_SNAP_RETAIN_COUNT
valueFrom:
configMapKeyRef:
name: zk-config
key: snap.retain
- name: ZK_PURGE_INTERVAL
valueFrom:
configMapKeyRef:
name: zk-config
key: purge.interval
- name: ZK_CLIENT_PORT
value: "2181"
- name: ZK_SERVER_PORT
value: "2888"
- name: ZK_ELECTION_PORT
value: "3888"
command: command:
- sh - sh
- -c - -c
- zkGenConfig.sh && zkServer.sh start-foreground - "start-zookeeper \
--servers=3 \
--data_dir=/var/lib/zookeeper/data \
--data_log_dir=/var/lib/zookeeper/data/log \
--conf_dir=/opt/zookeeper/conf \
--client_port=2181 \
--election_port=3888 \
--server_port=2888 \
--tick_time=2000 \
--init_limit=10 \
--sync_limit=5 \
--heap=512M \
--max_client_cnxns=60 \
--snap_retain_count=3 \
--purge_interval=12 \
--max_session_timeout=40000 \
--min_session_timeout=4000 \
--log_level=INFO"
readinessProbe: readinessProbe:
exec: exec:
command: command:
- "zkOk.sh" - sh
initialDelaySeconds: 15 - -c
- "zookeeper-ready 2181"
initialDelaySeconds: 10
timeoutSeconds: 5 timeoutSeconds: 5
livenessProbe: livenessProbe:
exec: exec:
command: command:
- "zkOk.sh" - sh
initialDelaySeconds: 15 - -c
- "zookeeper-ready 2181"
initialDelaySeconds: 10
timeoutSeconds: 5 timeoutSeconds: 5
volumeMounts: volumeMounts:
- name: datadir - name: datadir
@@ -154,4 +131,4 @@ spec:
accessModes: [ "ReadWriteOnce" ] accessModes: [ "ReadWriteOnce" ]
resources: resources:
requests: requests:
storage: 20Gi storage: 10Gi
+1 -1
View File
@@ -339,7 +339,7 @@ func TestExampleObjectSchemas(t *testing.T) {
"cassandra-statefulset": {&apps.StatefulSet{}, &storage.StorageClass{}}, "cassandra-statefulset": {&apps.StatefulSet{}, &storage.StorageClass{}},
"web": {&api.Service{}, &apps.StatefulSet{}}, "web": {&api.Service{}, &apps.StatefulSet{}},
"webp": {&api.Service{}, &apps.StatefulSet{}}, "webp": {&api.Service{}, &apps.StatefulSet{}},
"zookeeper": {&api.Service{}, &api.ConfigMap{}, &policy.PodDisruptionBudget{}, &apps.StatefulSet{}}, "zookeeper": {&api.Service{}, &api.Service{}, &policy.PodDisruptionBudget{}, &apps.StatefulSet{}},
}, },
} }