mirror of
https://github.com/jpetazzo/container.training.git
synced 2026-07-15 19:09:43 +00:00
🌈 Update HAProxy example to use literal blue/green deployment
This commit is contained in:
@@ -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.
|
||||
|
||||
147
k8s/rainbow.yaml
Normal file
147
k8s/rainbow.yaml
Normal file
@@ -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
|
||||
@@ -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.
|
||||
<br/>
|
||||
(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[
|
||||
|
||||
|
||||
Reference in New Issue
Block a user