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)
* [PersistentVolumes](/docs/concepts/storage/volumes/)
* [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/)
* [PodDisruptionBudgets](/docs/admin/disruptions/#specifying-a-poddisruptionbudget)
* [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
[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),
and a [StatefulSet](/docs/concepts/abstractions/controllers/statefulsets/).
{% include code.html language="yaml" file="zookeeper.yaml" ghlink="/docs/tutorials/stateful-application/zookeeper.yaml" %}
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.
```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,
the `zk-budget` PodDisruptionBudget, and the `zk` StatefulSet.
This creates the `zk-hs` Headless Service, the `zk-cs` Service,
the `zk-pdb` PodDisruptionBudget, and the `zk` StatefulSet.
```shell
service "zk-headless" created
configmap "zk-config" created
poddisruptionbudget "zk-budget" created
service "zk-hs" created
service "zk-cs" created
poddisruptionbudget "zk-pdb" 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
```
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`.
```shell
zk-0.zk-headless.default.svc.cluster.local
zk-1.zk-headless.default.svc.cluster.local
zk-2.zk-headless.default.svc.cluster.local
zk-0.zk-hs.default.svc.cluster.local
zk-1.zk-hs.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.
@@ -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
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
kubectl get pods -w -l app=zk
NAME READY STATUS RESTARTS AGE
@@ -281,18 +276,18 @@ endpoint will be the unique ZooKeeper server claiming the identity configured
in its `myid` file.
```shell
zk-0.zk-headless.default.svc.cluster.local
zk-1.zk-headless.default.svc.cluster.local
zk-2.zk-headless.default.svc.cluster.local
zk-0.zk-hs.default.svc.cluster.local
zk-1.zk-hs.default.svc.cluster.local
zk-2.zk-hs.default.svc.cluster.local
```
This ensures that the `servers` properties in the ZooKeepers' `zoo.cfg` files
represents a correctly configured ensemble.
```shell
server.1=zk-0.zk-headless.default.svc.cluster.local:2888:3888
server.2=zk-1.zk-headless.default.svc.cluster.local:2888:3888
server.3=zk-2.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-hs.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
@@ -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
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.
```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
ZooKeeper ensemble require consistent configuration in order to elect a leader
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
ConfigMaps to achieve this.
in order for the protocol to work correctly over a network. In our example we
achive consistent configuration by embedding the configuration directly into
the manifest.
Get the `zk-config` ConfigMap.
Get the `zk` StatefulSet.
```shell
kubectl get cm zk-config -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
```shell{% raw %}
kubectl get sts zk -o yaml
...
command:
- sh
- -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.
```shell
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
```
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
pass configuration to ensemble.
### 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
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
@@ -1029,19 +964,18 @@ cordon all but four of the nodes in your cluster.
kubectl cordon < node name >
```{% endraw %}
Get the `zk-budget` PodDisruptionBudget.
Get the `zk-pdb` PodDisruptionBudget.
```shell
kubectl get poddisruptionbudget zk-budget
kubectl get pdb zk-pdb
```
The `min-available` field indicates to Kubernetes that at least two Pods from
`zk` StatefulSet must be available at any time.
```yaml
NAME MIN-AVAILABLE ALLOWED-DISRUPTIONS AGE
zk-budget 2 1 1h
The `max-unavailable` field indicates to Kubernetes that at most one Pod from
`zk` StatefulSet can be unavailable at any time.
```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.
@@ -1,9 +1,10 @@
---
apiVersion: v1
kind: Service
metadata:
name: zk-headless
name: zk-hs
labels:
app: zk-headless
app: zk
spec:
ports:
- port: 2888
@@ -15,43 +16,45 @@ spec:
app: zk
---
apiVersion: v1
kind: ConfigMap
kind: Service
metadata:
name: zk-config
data:
ensemble: "zk-0;zk-1;zk-2"
jvm.heap: "2G"
tick: "2000"
init: "10"
sync: "5"
client.cnxns: "60"
snap.retain: "3"
purge.interval: "1"
name: zk-cs
labels:
app: zk
spec:
ports:
- port: 2181
name: client
selector:
app: zk
---
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
name: zk-budget
name: zk-pdb
spec:
selector:
matchLabels:
app: zk
minAvailable: 2
maxUnavailable: 1
---
apiVersion: apps/v1beta1
apiVersion: apps/v1beta2
kind: StatefulSet
metadata:
name: zk
spec:
serviceName: zk-headless
selector:
matchLabels:
app: zk
serviceName: zk-hs
replicas: 3
updateStrategy:
type: RollingUpdate
podManagementPolicy: Parallel
template:
metadata:
labels:
app: zk
annotations:
pod.alpha.kubernetes.io/initialized: "true"
spec:
affinity:
podAntiAffinity:
@@ -60,17 +63,17 @@ spec:
matchExpressions:
- key: "app"
operator: In
values:
- zk-headless
values:
- zk
topologyKey: "kubernetes.io/hostname"
containers:
- name: k8szk
- name: kubernetes-zookeeper
imagePullPolicy: Always
image: gcr.io/google_samples/k8szk:v1
image: "gcr.io/google_containers/kubernetes-zookeeper:1.0-3.4.10"
resources:
requests:
memory: "4Gi"
cpu: "1"
memory: "1Gi"
cpu: "0.5"
ports:
- containerPort: 2181
name: client
@@ -78,68 +81,42 @@ spec:
name: server
- containerPort: 3888
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:
- sh
- -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:
exec:
command:
- "zkOk.sh"
initialDelaySeconds: 15
- sh
- -c
- "zookeeper-ready 2181"
initialDelaySeconds: 10
timeoutSeconds: 5
livenessProbe:
exec:
command:
- "zkOk.sh"
initialDelaySeconds: 15
- sh
- -c
- "zookeeper-ready 2181"
initialDelaySeconds: 10
timeoutSeconds: 5
volumeMounts:
- name: datadir
@@ -154,4 +131,4 @@ spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 20Gi
storage: 10Gi