diff --git a/k8s/haproxy.cfg b/k8s/haproxy.cfg index 7d4bd01c..51a764ef 100644 --- a/k8s/haproxy.cfg +++ b/k8s/haproxy.cfg @@ -1,18 +1,16 @@ global daemon - maxconn 256 defaults mode tcp - timeout connect 5000ms - timeout client 50000ms - timeout server 50000ms + timeout connect 5s + timeout client 50s + timeout server 50s -frontend the-frontend +listen very-basic-load-balancer bind *:80 - default_backend the-backend - -backend the-backend - server google.com-80 google.com:80 maxconn 32 check - server ibm.fr-80 ibm.fr:80 maxconn 32 check + server blue color.blue.svc:80 + server green color.green.svc:80 +# Note: the services above must exist, +# otherwise HAproxy won't start. diff --git a/k8s/rainbow.yaml b/k8s/rainbow.yaml new file mode 100644 index 00000000..58976a17 --- /dev/null +++ b/k8s/rainbow.yaml @@ -0,0 +1,147 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: blue + labels: + app: rainbow +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: rainbow + color: blue + name: color + namespace: blue +spec: + selector: + matchLabels: + app: color + color: blue + template: + metadata: + labels: + app: color + color: blue + spec: + containers: + - image: jpetazzo/color + name: color +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: color + color: blue + name: color + namespace: blue +spec: + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 80 + selector: + app: color + color: blue + type: ClusterIP +--- +apiVersion: v1 +kind: Namespace +metadata: + name: green + labels: + app: rainbow +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: rainbow + color: green + name: color + namespace: green +spec: + selector: + matchLabels: + app: color + color: green + template: + metadata: + labels: + app: color + color: green + spec: + containers: + - image: jpetazzo/color + name: color +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: color + color: green + name: color + namespace: green +spec: + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 80 + selector: + app: color + color: green + type: ClusterIP +--- +apiVersion: v1 +kind: Namespace +metadata: + name: red + labels: + app: rainbow +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: rainbow + color: red + name: color + namespace: red +spec: + selector: + matchLabels: + app: color + color: red + template: + metadata: + labels: + app: color + color: red + spec: + containers: + - image: jpetazzo/color + name: color +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: color + color: red + name: color + namespace: red +spec: + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 80 + selector: + app: color + color: red + type: ClusterIP diff --git a/slides/k8s/configuration.md b/slides/k8s/configuration.md index 1effd876..43acd705 100644 --- a/slides/k8s/configuration.md +++ b/slides/k8s/configuration.md @@ -344,32 +344,94 @@ We'll cover them just after!* --- -## Passing a configuration file with a configmap +## Example: HAProxy configuration -- We will start a load balancer powered by HAProxy +- We are going to deploy HAProxy, a popular load balancer -- We will use the [official `haproxy` image](https://hub.docker.com/_/haproxy/) +- It expects to find its configuration in a specific place: -- It expects to find its configuration in `/usr/local/etc/haproxy/haproxy.cfg` + `/usr/local/etc/haproxy/haproxy.cfg` -- We will provide a simple HAproxy configuration, `k8s/haproxy.cfg` +- We will create a ConfigMap holding the configuration file -- It listens on port 80, and load balances connections between IBM and Google +- Then we will mount that ConfigMap in a Pod running HAProxy --- -## Creating the configmap +## Blue/green load balancing + +- In this example, we will deploy two versions of our app: + + - the "blue" version in the `blue` namespace + + - the "green" version in the `green` namespace + +- In both namespaces, we will have a Deployment and a Service + + (both named `color`) + +- We want to load balance traffic between both namespaces + + (we can't do that with a simple service selector: these don't cross namespaces) + +--- + +## Deploying the app + +- We're going to use the image `jpetazzo/color` + + (it is a simple "HTTP echo" server showing which pod served the request) + +- We can create each Namespace, Deployment, and Service by hand, or... .exercise[ -- Go to the `k8s` directory in the repository: +- We can deploy the app with a YAML manifest: ```bash - cd ~/container.training/k8s + kubectl apply -f ~/container.training/k8s/rainbow.yaml ``` -- Create a configmap named `haproxy` and holding the configuration file: +] + +--- + +## Testing the app + +- Reminder: Service `x` in Namespace `y` is available through: + + `x.y`, `x.y.svc`, `x.y.svc.cluster.local` + +- Since the `cluster.local` suffix can change, we'll use `x.y.svc` + +.exercise[ + +- Check that the app is up and running: ```bash - kubectl create configmap haproxy --from-file=haproxy.cfg + kubectl run --rm -it --restart=Never --image=nixery.dev/curl my-test-pod \ + curl color.blue.svc + ``` + +] + +--- + +## Creating the HAProxy configuration + +Here is the file that we will use, @@LINK[k8s/haproxy.cfg]: + +``` +@@INCLUDE[k8s/haproxy.cfg] +``` + +--- + +## Creating the ConfigMap + +.exercise[ + +- Create a ConfigMap named `haproxy` and holding the configuration file: + ```bash + kubectl create configmap haproxy --from-file=~/container.training/k8s/haproxy.cfg ``` - Check what our configmap looks like: @@ -381,37 +443,21 @@ We'll cover them just after!* --- -## Using the configmap +## Using the ConfigMap -We are going to use the following pod definition: +Here is @@LINK[k8s/haproxy.yaml], a Pod manifest using that ConfigMap: ```yaml -apiVersion: v1 -kind: Pod -metadata: - name: haproxy -spec: - volumes: - - name: config - configMap: - name: haproxy - containers: - - name: haproxy - image: haproxy - volumeMounts: - - name: config - mountPath: /usr/local/etc/haproxy/ +@@INCLUDE[k8s/haproxy.yaml] ``` --- -## Using the configmap - -- The resource definition from the previous slide is in `k8s/haproxy.yaml` +## Creating the Pod .exercise[ -- Create the HAProxy pod: +- Create the HAProxy Pod: ```bash kubectl apply -f ~/container.training/k8s/haproxy.yaml ``` @@ -430,27 +476,21 @@ spec: ## Testing our load balancer -- The load balancer will send: +- If everything went well, when we should see a perfect round robin - - half of the connections to Google - - - the other half to IBM + (one request to `blue`, one request to `green`, one request to `blue`, etc.) .exercise[ -- Access the load balancer a few times: +- Send a few requests: ```bash + for i in $(seq 10); do curl $IP - curl $IP - curl $IP + done ``` ] -We should see connections served by Google, and others served by IBM. -
-(Each server sends us a redirect page. Look at the URL that they send us to!) - --- ## Exposing configmaps with the downward API @@ -490,27 +530,14 @@ We should see connections served by Google, and others served by IBM. We are going to use the following pod definition: ```yaml -apiVersion: v1 -kind: Pod -metadata: - name: registry -spec: - containers: - - name: registry - image: registry - env: - - name: REGISTRY_HTTP_ADDR - valueFrom: - configMapKeyRef: - name: registry - key: http.addr +@@INCLUDE[k8s/registry.yaml] ``` --- ## Using the configmap -- The resource definition from the previous slide is in `k8s/registry.yaml` +- The resource definition from the previous slide is in @@LINK[k8s/registry.yaml] .exercise[