From 9fa7b958dca8dd4b670e2ccaf7dc6fe14c4d9ff9 Mon Sep 17 00:00:00 2001 From: Jerome Petazzoni Date: Thu, 6 Dec 2018 21:38:26 -0600 Subject: [PATCH] Update Consul demo to use Cloud auto-join Consul 1.4 introduces Cloud auto-join, which finds the IP addresses of the other nodes by querying an API (in that case, the Kubernetes API). This involves creating a service account and granting permissions to list and get pods. It is a little bit more complex, but it reuses previous notions (like RBAC) so I like it better. --- k8s/consul.yaml | 46 ++++++++++++++++++++++++++------- slides/k8s/statefulsets.md | 52 ++++++++++++++++++++++++-------------- 2 files changed, 70 insertions(+), 28 deletions(-) diff --git a/k8s/consul.yaml b/k8s/consul.yaml index 2e5bc138..a82d4733 100644 --- a/k8s/consul.yaml +++ b/k8s/consul.yaml @@ -1,3 +1,37 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: consul + labels: + app: consul +rules: + - apiGroups: [""] + resources: + - pods + verbs: + - get + - list +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: consul +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: consul +subjects: + - kind: ServiceAccount + name: consul + namespace: default +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: consul + labels: + app: consul +--- apiVersion: v1 kind: Service metadata: @@ -24,6 +58,7 @@ spec: labels: app: consul spec: + serviceAccountName: consul affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: @@ -37,18 +72,11 @@ spec: terminationGracePeriodSeconds: 10 containers: - name: consul - image: "consul:1.2.2" - env: - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace + image: "consul:1.4.0" args: - "agent" - "-bootstrap-expect=3" - - "-retry-join=consul-0.consul.$(NAMESPACE).svc.cluster.local" - - "-retry-join=consul-1.consul.$(NAMESPACE).svc.cluster.local" - - "-retry-join=consul-2.consul.$(NAMESPACE).svc.cluster.local" + - "-retry-join=provider=k8s label_selector=\"app=consul\"" - "-client=0.0.0.0" - "-data-dir=/consul/data" - "-server" diff --git a/slides/k8s/statefulsets.md b/slides/k8s/statefulsets.md index 35c7fc20..3dc45286 100644 --- a/slides/k8s/statefulsets.md +++ b/slides/k8s/statefulsets.md @@ -266,7 +266,9 @@ spec: --- -## Stateful sets in action +# Running a Consul cluster + +- Here is a good use-case for Stateful sets! - We are going to deploy a Consul cluster with 3 nodes @@ -294,42 +296,54 @@ consul agent -data=dir=/consul/data -client=0.0.0.0 -server -ui \ -retry-join=`Y.Y.Y.Y` ``` -- We need to replace X.X.X.X and Y.Y.Y.Y with the addresses of other nodes +- Replace X.X.X.X and Y.Y.Y.Y with the addresses of other nodes -- We can specify DNS names, but then they have to be FQDN - -- It's OK for a pod to include itself in the list as well - -- We can therefore use the same command-line on all nodes (easier!) +- The same command-line can be used on all nodes (convenient!) --- -## Discovering the addresses of other pods +## Cloud Auto-join -- When a service is created for a stateful set, individual DNS entries are created +- Since version 1.4.0, Consul can use the Kubernetes API to find its peers -- These entries are constructed like this: +- This is called [Cloud Auto-join] - `-...svc.cluster.local` +- Instead of passing an IP address, we need to pass a parameter like this: -- `` is the number of the pod in the set (starting at zero) + ``` + consul agent -retry-join "provider=k8s label_selector=\"app=consul\"" + ``` -- If we deploy Consul in the default namespace, the names could be: +- Consul needs to be able to talk to the Kubernetes API - - `consul-0.consul.default.svc.cluster.local` - - `consul-1.consul.default.svc.cluster.local` - - `consul-2.consul.default.svc.cluster.local` +- We can provide a `kubeconfig` file + +- If Consul runs in a pod, it will use the *service account* of the pod + +[Cloud Auto-join]: https://www.consul.io/docs/agent/cloud-auto-join.html#kubernetes-k8s- + +--- + +## Setting up Cloud auto-join + +- We need to create a service account for Consul + +- We need to create a role that can `list` and `get` pods + +- We need to bind that role to the service account + +- And of course, we need to make sure that Consul pods use that service account --- ## Putting it all together -- The file `k8s/consul.yaml` defines a service and a stateful set +- The file `k8s/consul.yaml` defines the required resources + + (service account, cluster role, cluster role binding, service, stateful set) - It has a few extra touches: - - the name of the namespace is injected through an environment variable - - a `podAntiAffinity` prevents two pods from running on the same node - a `preStop` hook makes the pod leave the cluster when shutdown gracefully