├── LICENSE ├── README.md ├── cheatsheets └── README.md ├── exercise01 ├── Dockerfile ├── index.html └── solution.md ├── exercise02 └── Readme.md ├── exercise03 └── README.md ├── finaltest ├── README.md ├── certs │ ├── nginx.crt │ └── nginx.key ├── conf │ └── ssl-nginx.conf ├── solution.md └── solution │ ├── configmap.yaml │ ├── deployment.yaml │ ├── secret.yaml │ └── service.yaml ├── pingponredis └── deployment.yaml ├── pingredis ├── ping-svc.yaml ├── pingredis-dep.yaml ├── redis-dep.yaml └── redis-svc.yaml └── secrets ├── pod-secret.yaml └── secret.yaml /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Kube.camp 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kubernetes_in_one_day 2 | Material for the training course 3 | -------------------------------------------------------------------------------- /cheatsheets/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Useful Commands 4 | 5 | Get kubectl version 6 | 7 | kubectl version 8 | 9 | Get cluster info: 10 | 11 | kubectl cluster-info 12 | 13 | 14 | ## Viewing, Finding Resources 15 | 16 | 17 | ### Columnar output 18 | 19 | kubectl get services # List all services in the namespace 20 | kubectl get pods --all-namespaces # List all pods in all namespaces 21 | kubectl get pods -o wide # List all pods in the namespace, with more details 22 | kubectl get rc # List a particular replication controller 23 | kubectl get pods -l env=production # List all pods with a label env=production 24 | 25 | ### Verbose output 26 | 27 | kubectl describe nodes 28 | kubectl describe pods 29 | kubectl describe pods # Lists pods created by using common prefix 30 | 31 | ### List Services Sorted by Name 32 | 33 | kubectl get services --sort-by=.metadata.name 34 | 35 | ### List pods Sorted by Restart Count 36 | 37 | kubectl get pods --sort-by=.status.containerStatuses[0].restartCount 38 | 39 | ### Get the version label of all pods with label app=cassandra 40 | 41 | kubectl get pods --selector=app=cassandra rc -o 'jsonpath={.items[*].metadata.labels.version}' 42 | 43 | ### Get ExternalIPs of all nodes 44 | 45 | kubectl get nodes -o jsonpath='{.items[*].status.addresses[?(@.type=ExternalIP)].address}' 46 | 47 | 48 | ### Check which nodes are ready 49 | kubectl get nodes -o jsonpath='{range .items[*]}{@.metadata.name}:{range @.status.conditions[*]}{@.type}={@.status};{end}{end}'| tr ';' "\n" | grep "Ready=True" 50 | 51 | 52 | ## Creating Objects 53 | 54 | kubectl create -f ./file.yml 55 | kubectl create -f ./file1.yml -f ./file2.yaml 56 | kubectl create -f ./dir 57 | kubectl create -f http://www.fpaste.org/279276/48569091/raw/ 58 | 59 | ### Create multiple YAML objects from stdin 60 | cat < new-label=awesome # Add a Label 103 | kubectl annotate pods icon-url=http://goo.gl/XXBTWq # Add an annotation 104 | kubectl delete pod pingredis-XXXXX 105 | 106 | ## Scaling up & down 107 | 108 | kubectl scale --replicas=3 deployment nginx 109 | 110 | 111 | ### Interacting with running Pods 112 | 113 | 114 | kubectl logs 115 | kubectl logs -f 116 | 117 | kubectl run -i --tty busybox --image=busybox -- sh # Run pod as interactive shell 118 | kubectl attach -i # Attach to Running Container 119 | kubectl port-forward # Forward port of Pod to your local machine 120 | kubectl port-forward # Forward port to service 121 | kubectl exec -- ls / # Run command in existing pod (1 container case) 122 | kubectl exec -c -- ls / # Run command in existing pod (multi-container case) 123 | 124 | 125 | ## Checking that the DNS works: 126 | 127 | kubectl exec busybox -- nslookup kubernetes 128 | kubectl exec busybox -- nslookup kubernetes.default 129 | kubectl exec busybox -- nslookup kubernetes.default.svc.cluster.local 130 | 131 | 132 | ## Create an expose a deployment 133 | kubectl run nginx --image=nginx:1.9.12 134 | kubectl expose deployment nginx --port=80 --type=LoadBalancer 135 | 136 | ## Create a ConfigMap from a file 137 | 138 | kubectl create configmap nginx-ghost --from-file=configs/ghost.conf --namespace=ghost 139 | 140 | ## Create a secret from a file 141 | 142 | kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt 143 | 144 | ## Handy bash Aliases 145 | 146 | alias k="kubectl" 147 | alias kc="kubectl create -f" 148 | alias kg="kubectl get" 149 | alias pods="kubectl get pods" 150 | alias allpods="kubectl get pods --all-namespaces" 151 | alias rcs="kubectl get rc" 152 | alias svcs="kubectl get services" 153 | alias dep="kubectl get deployment" 154 | alias kd="kubectl describe" 155 | alias kdp="kubectl describe pod " 156 | alias kds="kubectl describe service " 157 | alias nodes="kubectl get nodes" 158 | alias klogs="kubectl logs" 159 | alias ns="kubectl get ns" 160 | alias deploys="kubectl get deployment" 161 | alias events="kubectl get events" 162 | alias kexec="kubectl exec -it " 163 | alias secrets="kubectl get secrets" 164 | alias igs="kubectl get ingress" 165 | alias contexts="kubectl config get-contexts" 166 | alias ktop="kubectl top nodes" 167 | 168 | ## Handy bash functions 169 | 170 | 171 | ### Delete pod, don't wait 172 | 173 | function dp(){ 174 | kubectl delete pod $1 --grace-period=0 175 | } 176 | 177 | ### Secrets related functions 178 | 179 | function encode(){ 180 | echo -n "$1" | base64 181 | } 182 | 183 | 184 | function decode(){ 185 | echo -n "$1" | base64 -D 186 | } 187 | 188 | function gettoken(){ 189 | kubectl get secret $(kubectl get secret | grep default | awk '{print $1}') -o yaml | grep "token:" | awk '{print $2}' | base64 -D 190 | } 191 | 192 | 193 | ### set context quickly 194 | 195 | function context(){ 196 | kubectl config use-context $1 197 | } 198 | 199 | ### run bash in a pod 200 | 201 | function dex(){ 202 | docker exec -it $1 bash 203 | } 204 | 205 | -------------------------------------------------------------------------------- /exercise01/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx 2 | 3 | COPY index.html /usr/share/nginx/html 4 | -------------------------------------------------------------------------------- /exercise01/index.html: -------------------------------------------------------------------------------- 1 |

Super hello

2 | -------------------------------------------------------------------------------- /exercise01/solution.md: -------------------------------------------------------------------------------- 1 | # Exercise 1 2 | 3 | ## Create and run a web server with a custom page 4 | 5 | echo "

Hello Kube.camp

" >> index.html 6 | echo "FROM nginx:alpine" >> Dockerfile 7 | echo "COPY index.html /usr/share/nginx/html" >> Dockerfile 8 | docker build -t ipedrazas/hello:kubecamp . 9 | docker push ipedrazas/hello:kubecamp 10 | 11 | kubectl run hello --image=ipedrazas/hello:kubecamp --port=80 12 | -------------------------------------------------------------------------------- /exercise02/Readme.md: -------------------------------------------------------------------------------- 1 | # Exercise 02 2 | 3 | Now that you have deployed a web server, let's interact with it. 4 | 5 | 6 | First, let's get the pods: 7 | 8 | kubectl get pods 9 | 10 | now, let's read the logs of that pod: 11 | 12 | kubectl get logs hello-1767487725-smthc 13 | 14 | Let's send some traffic... so, how do we access the pod? a solution is to bind the 15 | pod port to our localhost: 16 | 17 | kubectl port-forward hello-1767487725-smthc 8000:80 18 | 19 | Let's try to access our website: 20 | 21 | curl localhost:8000 22 | 23 | let's read the logs again: 24 | 25 | kubectl get logs hello-1767487725-smthc 26 | 27 | Can we tail the logs? 28 | 29 | kubectl get logs hello-1767487725-smthc -f 30 | 31 | or 32 | 33 | kubectl get logs -f hello-1767487725-smthc 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /exercise03/README.md: -------------------------------------------------------------------------------- 1 | # Exercise 03 2 | 3 | ## Services 4 | 5 | Binding our pod to our localhost can be great for development, but it's nbot going to 6 | work very well in prod. Yes, `it works in my machine is as true as useless`. 7 | 8 | Let's expose our pods to the world using a service: 9 | 10 | kubectl expose deployment hello 11 | 12 | So, we have a service that sends traffic to our pods. Excellene, let's look at it: 13 | 14 | 15 | kubectl get svc 16 | 17 | What about if we want to look at our service? 18 | 19 | kubectl describe svc hello 20 | 21 | What if I want to access the pod from outside my cluster? 22 | 23 | kubectl expose deployment hello --name=public-hello --type=LoadBalancer 24 | 25 | Or 26 | 27 | kubectl expose deployment hello --name=public-hello --type=NodePort 28 | 29 | Next you have to access that service. To get the IP/port you will have to do: 30 | 31 | 32 | kubectl describe svc public-hello 33 | 34 | If you're using `minikube` you need to get the ip of minikube: 35 | 36 | minikube ip 37 | 38 | or you can ask minikube to open your service 39 | 40 | minikube service public-hello 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /finaltest/README.md: -------------------------------------------------------------------------------- 1 | # All together, now! 2 | 3 | By now, we have covered: 4 | 5 | * Deployments 6 | * ReplicaSets 7 | * Pods 8 | * Services 9 | * ConfigMaps 10 | * Secrets 11 | * Jobs 12 | 13 | 14 | Let's see if we can do an exercise that brings all these things together. 15 | 16 | ## The Challenge 17 | 18 | We need to run a web server that uses SSL certificates with, at least, 3 instances. 19 | 20 | 21 | ## A layeRED challenge 22 | 23 | Business has decided that we have to go live today. You need to deploy a database, a microservice that reads data from that database and a web frontend highly available. To make things worse, the CEO has decide to broadcast live the new launch of the platform and he has requested that with only one command the platform goes from zero to live. 24 | 25 | It's your duty as the CTO to deliver! 26 | 27 | -------------------------------------------------------------------------------- /finaltest/certs/nginx.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEmzCCA4OgAwIBAgIJAJ4QHUwlef0EMA0GCSqGSIb3DQEBBQUAMIGPMQswCQYD 3 | VQQGEwJVSzEPMA0GA1UECBMGTG9uZG9uMQ8wDQYDVQQHEwZMb25kb24xEjAQBgNV 4 | BAoTCWt1YmUuY2FtcDEPMA0GA1UECxMGZGlyZWN0MRYwFAYDVQQDEw1sYWIua3Vi 5 | ZS5jYW1wMSEwHwYJKoZIhvcNAQkBFhJpbmZvQGxhYi5rdWJlLmNhbXAwHhcNMTcw 6 | MTI3MTYwMDQzWhcNMTgwMTI3MTYwMDQzWjCBjzELMAkGA1UEBhMCVUsxDzANBgNV 7 | BAgTBkxvbmRvbjEPMA0GA1UEBxMGTG9uZG9uMRIwEAYDVQQKEwlrdWJlLmNhbXAx 8 | DzANBgNVBAsTBmRpcmVjdDEWMBQGA1UEAxMNbGFiLmt1YmUuY2FtcDEhMB8GCSqG 9 | SIb3DQEJARYSaW5mb0BsYWIua3ViZS5jYW1wMIIBIjANBgkqhkiG9w0BAQEFAAOC 10 | AQ8AMIIBCgKCAQEAyq10LMj3GJ/gBmNzLkoNvsQG5AmCrBDTDkW9BRDrWhgygj/t 11 | ZSvUf3dLaVvOHcilqljGJqdOHbPH4fWS4txQnPGKU0ZocS2RPuqk3kBJjDHcCFwf 12 | 3cGRwiLsKn0CtaxJLb5hd1F7urb86gWT7KsX7w+DsgK2PFrOXRkXGhQ8nc+/x290 13 | JEwzwwDr+4zU3i8GZeWQqCiu25F5XM9v9X7ljeGti5gEfmRSi9+jc68P0hmYjAAc 14 | 0pOnJXwqWSd7s6P6lvGwvMf/NAHepzCmSOpR5aigahDW4NexO5eOorehXQ++PaBw 15 | azMWzCHFGRuLvfxkFbxei4xLBYD01Z1i90L5hQIDAQABo4H3MIH0MB0GA1UdDgQW 16 | BBSjDkmu5+1UEoGRAiz2164dHl+m7zCBxAYDVR0jBIG8MIG5gBSjDkmu5+1UEoGR 17 | Aiz2164dHl+m76GBlaSBkjCBjzELMAkGA1UEBhMCVUsxDzANBgNVBAgTBkxvbmRv 18 | bjEPMA0GA1UEBxMGTG9uZG9uMRIwEAYDVQQKEwlrdWJlLmNhbXAxDzANBgNVBAsT 19 | BmRpcmVjdDEWMBQGA1UEAxMNbGFiLmt1YmUuY2FtcDEhMB8GCSqGSIb3DQEJARYS 20 | aW5mb0BsYWIua3ViZS5jYW1wggkAnhAdTCV5/QQwDAYDVR0TBAUwAwEB/zANBgkq 21 | hkiG9w0BAQUFAAOCAQEAwU1huAQfYrII0ACeMqe66Mi9mDbFzr8hImbUDPc722ae 22 | Dgj7UkNl3hb6h3C1z/nwwAzCa1pReI8L4pUPWJGGldCxB01JZWkjcRD2udYj1xc+ 23 | rVHCfIsZQ8e1LwmMQG+YdO72UhyoKfTU8DyoXvZSVoUCTDlK1A8L5+AvwZGRXnCt 24 | f6R+Pi8xCi2XudOe/gIkUWOLIb0tF/dYJkkYtLQaJHV1q4XWlikZ+/fttP3HZMTE 25 | nZNugAeWK/nJEg3t2w6bk/bEj6BvTIrm8WHHDKUnaLfWKex8itLyvj2Wj1OZR+1W 26 | y4LS28d5QJhaFM/tmo8StIWp9qg37xEhJ99iZoCA0A== 27 | -----END CERTIFICATE----- 28 | -------------------------------------------------------------------------------- /finaltest/certs/nginx.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAyq10LMj3GJ/gBmNzLkoNvsQG5AmCrBDTDkW9BRDrWhgygj/t 3 | ZSvUf3dLaVvOHcilqljGJqdOHbPH4fWS4txQnPGKU0ZocS2RPuqk3kBJjDHcCFwf 4 | 3cGRwiLsKn0CtaxJLb5hd1F7urb86gWT7KsX7w+DsgK2PFrOXRkXGhQ8nc+/x290 5 | JEwzwwDr+4zU3i8GZeWQqCiu25F5XM9v9X7ljeGti5gEfmRSi9+jc68P0hmYjAAc 6 | 0pOnJXwqWSd7s6P6lvGwvMf/NAHepzCmSOpR5aigahDW4NexO5eOorehXQ++PaBw 7 | azMWzCHFGRuLvfxkFbxei4xLBYD01Z1i90L5hQIDAQABAoIBAQC94WlA9/p/iHDi 8 | q1Nin6BnA9IM3FgfChghe/aNg39rRdY0Lt4i9cA8ty/gglEFmFCU2lyyI/ZMX305 9 | VdAKWCvyDVzxjboVpoI4Nq7FRedhv+iLsHtuT4ZWIk+tsrbSK5nXkFBR7/YCRKOI 10 | QDeI9/YRUzCnmmDPBKfnkrURCrqLgUacf8qsNkhDe3wVBP4Eu63IXWwEnHHXVvFX 11 | tVtFRMk2A8F2MX2YkMPcwYnST1q5O7wDKaL/n3vzOnnANAwdWEEXn2+gpnxV7kht 12 | shcbmxvYUMWukVgJmQy1Rq3vuhEpZ4EfjAsMxdare3SmSNHXYQSrHfwTMnPVxrAg 13 | r5vm6MjVAoGBAPAhEelF7ywc0h8K0F4ovkm8cxb80ewULJbXsHS6b8GaQEXNIBTI 14 | cQ9OADN4PjSbRULzjKEsLyzFkp84470fSQVORXsgrTu9giQt8Jv/C86fKOUcEiTz 15 | GqVWwGAuiqAFAT+4haULs5grgPUDcbvGlqnVgh7Cbc2ZMUQq0QPU73trAoGBANgS 16 | tgWIpebKa6jeTYCDJDNNqxyJQpQumOETHOR/CrGdHEKfpewO3cz8UJxMxgeYc3TI 17 | jjVggrEO5NlHjvBrYn+0t7QbOORbrJ6PK8PVn8GscHz4URj1zUOr43BSMdz1mtTd 18 | ZoAz615zUooJ+XLFIY6N86FiIaq7RjjAlKPrZArPAoGACLpK+l2OWd4aTQKJnEKC 19 | 2A8/Z6B8yMXa8QiZ40Q7d5/xohfYiKjYYyQEodpG+IaEN/C+NcVzWX882wioTmFq 20 | uASmRdlkMn2q00HQMvtMJJBoXhttFWa4mzXR/Cz04OgNqZE9WkhYmLlMEJu1cIvB 21 | Qh7+gbuzXfupbL7ZpfgBVE0CgYAIiFSfy1Gh14SA2qZ82LDpRbvoGJOEfoKTAMo3 22 | S70EXovrJZrLw5qGqcAVLAL18dM9XV4gRXtjuo7W9bhzTgpJuL04Y4rPmb8rU8QK 23 | q7jvUPvwM24gajR846DLorNNYnWGymdt0J8Oz8cGpHYxTg+RLZHdYZ6qu1J+kzxL 24 | bNQ6iQKBgDIBesO1AC8R2PdFUZWrtl798V14GuFC0tTw+NRfbxM1ZuvUbZ+I87gM 25 | 8TNSvEKEgnct43OFAk0cscK9p72LrO5nyCn802y3/h1to3OAvE4cxDViHZ3e/0Vg 26 | LqByCS61d5PTg1y4Dno3NxFvsX9nKTlqJPS4e8j5rwUWMZd+Vmjy 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /finaltest/conf/ssl-nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80 default_server; 3 | listen [::]:80 default_server ipv6only=on; 4 | 5 | listen 443 ssl; 6 | 7 | root /usr/share/nginx/html; 8 | index index.html index.htm; 9 | 10 | server_name your_domain.com; 11 | ssl_certificate /etc/nginx/ssl/nginx.crt; 12 | ssl_certificate_key /etc/nginx/ssl/nginx.key; 13 | 14 | location / { 15 | try_files $uri $uri/ =404; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /finaltest/solution.md: -------------------------------------------------------------------------------- 1 | # Create self-signed Certificate 2 | 3 | To create a self-signed certificate we need to execute teh following command: 4 | 5 | sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout certs/nginx.key -out certs/nginx.crt 6 | 7 | The command will ask a few questions, the important one is to put the right FQDN (we use lab.kube.camp), which it will be the domain we want to use with this certificate. 8 | 9 | Modify your file `/etc/hosts` with 10 | 11 | 127.0.0.1 lab.kube.camp 12 | 13 | Once we have the certificate, we need to configure nginx. Create a file called `ssl-nginx.conf` with this content: 14 | 15 | server { 16 | listen 80 default_server; 17 | listen [::]:80 default_server ipv6only=on; 18 | 19 | listen 443 ssl; 20 | 21 | root /usr/share/nginx/html; 22 | index index.html index.htm; 23 | 24 | server_name lab.kube.camp; 25 | ssl_certificate /etc/nginx/ssl/nginx.crt; 26 | ssl_certificate_key /etc/nginx/ssl/nginx.key; 27 | 28 | location / { 29 | try_files $uri $uri/ =404; 30 | } 31 | } 32 | 33 | 34 | 35 | Try to run a docker container using these certificates and verify that it works 36 | 37 | docker run -d --rm -p 8443:443 -p 8000:80 -v $(pwd)/conf/ssl-nginx.conf:/etc/nginx/conf.d/default.conf:ro -v $(pwd)/certs:/etc/nginx/ssl nginx 38 | 39 | 40 | Test it by doing 41 | 42 | curl http://lab.kube.camp:8000 43 | 44 | and 45 | 46 | curl -k https://lab.kube.camp:8443 47 | 48 | 49 | Now it's time to turn this into kubernetes manifests. We are going to create: 50 | 51 | * Secret: containing the certificates 52 | * ConfigMap: containing the nginx conf 53 | * Deployment: containing nginx image. We will mount the secret and configmap as two volumes 54 | 55 | 56 | To create the secret you can create a `yaml` file or you can execute the following command: 57 | 58 | kubectl create secret tls nginx-ssl --cert=certs/nginx.crt --key=certs/nginx.key 59 | 60 | To create the configmap, you can create it using the following command, or creating the file: 61 | 62 | kubectl create configmap nginx-config --from-file=conf/ssl-nginx.conf 63 | 64 | Finally, you have to create a deployment for nginx and a service: 65 | 66 | Service: 67 | 68 | apiVersion: v1 69 | kind: Service 70 | metadata: 71 | labels: 72 | run: nginx 73 | name: nginx 74 | spec: 75 | type: NodePort 76 | ports: 77 | - port: 80 78 | protocol: TCP 79 | targetPort: 80 80 | name: http 81 | - port: 443 82 | protocol: TCP 83 | targetPort: 443 84 | name: https 85 | selector: 86 | run: nginx 87 | 88 | Deployment: 89 | 90 | apiVersion: extensions/v1beta1 91 | kind: Deployment 92 | metadata: 93 | labels: 94 | run: nginx 95 | name: nginx 96 | spec: 97 | replicas: 1 98 | selector: 99 | matchLabels: 100 | run: nginx 101 | strategy: 102 | rollingUpdate: 103 | maxSurge: 1 104 | maxUnavailable: 1 105 | type: RollingUpdate 106 | template: 107 | metadata: 108 | labels: 109 | run: nginx 110 | spec: 111 | containers: 112 | - image: nginx:alpine 113 | imagePullPolicy: Always 114 | name: nginx 115 | ports: 116 | - containerPort: 80 117 | protocol: TCP 118 | - containerPort: 443 119 | protocol: TCP 120 | volumeMounts: 121 | - name: nginx-certs 122 | readOnly: true 123 | mountPath: /etc/nginx/ssl 124 | - name: config-nginx 125 | mountPath: /etc/nginx/conf.d 126 | volumes: 127 | - name: nginx-certs 128 | secret: 129 | secretName: nginx-ssl 130 | - name: config-nginx 131 | configMap: 132 | name: nginx-config 133 | items: 134 | - key: ssl-nginx.conf 135 | path: default.conf 136 | 137 | To deploy, you can use `kubectl` 138 | 139 | kubectl create -f . 140 | 141 | ## Test your deployment 142 | 143 | First, you need to know which ports your services have been used: 144 | 145 | kubectl get svc 146 | 147 | You should see something like this: 148 | 149 | NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE 150 | kubernetes 10.0.0.1 443/TCP 3d 151 | nginx 10.0.0.9 80:31732/TCP,443:32269/TCP 4m 152 | 153 | Note the `PORTS` column, it says that the port 80 of the service has been bound to the port 31732 of teh host. If you're using minikube to do this exercise, you need to get the IP of minikube: 154 | 155 | minikube ip 156 | 157 | Set that ip in your file `/etc/hosts` as the domain you used to create the certificates (you had previously it set to 127.0.0.1 during the docker test). 158 | 159 | Test it by doing 160 | 161 | curl http://lab.kube.camp:31732 162 | 163 | and 164 | 165 | curl -k https://lab.kube.camp:32269 166 | 167 | Excellent, time to scale: 168 | 169 | kubectl scale deployment nginx --scale=3 170 | 171 | Congratulate yourself if you get 200 OK twice! 172 | -------------------------------------------------------------------------------- /finaltest/solution/configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: nginx-config 5 | labels: 6 | app: ssl-nginx 7 | data: 8 | ssl-nginx.conf: | 9 | server { 10 | listen 80 default_server; 11 | listen [::]:80 default_server ipv6only=on; 12 | 13 | listen 443 ssl; 14 | 15 | root /usr/share/nginx/html; 16 | index index.html index.htm; 17 | 18 | server_name your_domain.com; 19 | ssl_certificate /etc/nginx/ssl/tls.crt; 20 | ssl_certificate_key /etc/nginx/ssl/tls.key; 21 | 22 | location / { 23 | try_files $uri $uri/ =404; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /finaltest/solution/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | labels: 5 | run: nginx 6 | name: nginx 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | run: nginx 12 | strategy: 13 | rollingUpdate: 14 | maxSurge: 1 15 | maxUnavailable: 1 16 | type: RollingUpdate 17 | template: 18 | metadata: 19 | labels: 20 | run: nginx 21 | spec: 22 | containers: 23 | - image: nginx:alpine 24 | imagePullPolicy: Always 25 | name: nginx 26 | ports: 27 | - containerPort: 80 28 | protocol: TCP 29 | - containerPort: 443 30 | protocol: TCP 31 | volumeMounts: 32 | - name: nginx-certs 33 | readOnly: true 34 | mountPath: /etc/nginx/ssl 35 | - name: config-nginx 36 | mountPath: /etc/nginx/conf.d 37 | volumes: 38 | - name: nginx-certs 39 | secret: 40 | secretName: nginx-ssl 41 | - name: config-nginx 42 | configMap: 43 | name: nginx-config 44 | items: 45 | - key: ssl-nginx.conf 46 | path: default.conf 47 | -------------------------------------------------------------------------------- /finaltest/solution/secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: nginx-ssl 5 | type: kubernetes.io/tls 6 | data: 7 | tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVtekNDQTRPZ0F3SUJBZ0lKQUo0UUhVd2xlZjBFTUEwR0NTcUdTSWIzRFFFQkJRVUFNSUdQTVFzd0NRWUQKVlFRR0V3SlZTekVQTUEwR0ExVUVDQk1HVEc5dVpHOXVNUTh3RFFZRFZRUUhFd1pNYjI1a2IyNHhFakFRQmdOVgpCQW9UQ1d0MVltVXVZMkZ0Y0RFUE1BMEdBMVVFQ3hNR1pHbHlaV04wTVJZd0ZBWURWUVFERXcxc1lXSXVhM1ZpClpTNWpZVzF3TVNFd0h3WUpLb1pJaHZjTkFRa0JGaEpwYm1adlFHeGhZaTVyZFdKbExtTmhiWEF3SGhjTk1UY3cKTVRJM01UWXdNRFF6V2hjTk1UZ3dNVEkzTVRZd01EUXpXakNCanpFTE1Ba0dBMVVFQmhNQ1ZVc3hEekFOQmdOVgpCQWdUQmt4dmJtUnZiakVQTUEwR0ExVUVCeE1HVEc5dVpHOXVNUkl3RUFZRFZRUUtFd2xyZFdKbExtTmhiWEF4CkR6QU5CZ05WQkFzVEJtUnBjbVZqZERFV01CUUdBMVVFQXhNTmJHRmlMbXQxWW1VdVkyRnRjREVoTUI4R0NTcUcKU0liM0RRRUpBUllTYVc1bWIwQnNZV0l1YTNWaVpTNWpZVzF3TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQwpBUThBTUlJQkNnS0NBUUVBeXExMExNajNHSi9nQm1Oekxrb052c1FHNUFtQ3JCRFREa1c5QlJEcldoZ3lnai90ClpTdlVmM2RMYVZ2T0hjaWxxbGpHSnFkT0hiUEg0ZldTNHR4UW5QR0tVMFpvY1MyUlB1cWsza0JKakRIY0NGd2YKM2NHUndpTHNLbjBDdGF4SkxiNWhkMUY3dXJiODZnV1Q3S3NYN3crRHNnSzJQRnJPWFJrWEdoUThuYysveDI5MApKRXd6d3dEcis0elUzaThHWmVXUXFDaXUyNUY1WE05djlYN2xqZUd0aTVnRWZtUlNpOStqYzY4UDBobVlqQUFjCjBwT25KWHdxV1NkN3M2UDZsdkd3dk1mL05BSGVwekNtU09wUjVhaWdhaERXNE5leE81ZU9vcmVoWFErK1BhQncKYXpNV3pDSEZHUnVMdmZ4a0ZieGVpNHhMQllEMDFaMWk5MEw1aFFJREFRQUJvNEgzTUlIME1CMEdBMVVkRGdRVwpCQlNqRGttdTUrMVVFb0dSQWl6MjE2NGRIbCttN3pDQnhBWURWUjBqQklHOE1JRzVnQlNqRGttdTUrMVVFb0dSCkFpejIxNjRkSGwrbTc2R0JsYVNCa2pDQmp6RUxNQWtHQTFVRUJoTUNWVXN4RHpBTkJnTlZCQWdUQmt4dmJtUnYKYmpFUE1BMEdBMVVFQnhNR1RHOXVaRzl1TVJJd0VBWURWUVFLRXdscmRXSmxMbU5oYlhBeER6QU5CZ05WQkFzVApCbVJwY21WamRERVdNQlFHQTFVRUF4TU5iR0ZpTG10MVltVXVZMkZ0Y0RFaE1COEdDU3FHU0liM0RRRUpBUllTCmFXNW1iMEJzWVdJdWEzVmlaUzVqWVcxd2dna0FuaEFkVENWNS9RUXdEQVlEVlIwVEJBVXdBd0VCL3pBTkJna3EKaGtpRzl3MEJBUVVGQUFPQ0FRRUF3VTFodUFRZllySUkwQUNlTXFlNjZNaTltRGJGenI4aEltYlVEUGM3MjJhZQpEZ2o3VWtObDNoYjZoM0Mxei9ud3dBekNhMXBSZUk4TDRwVVBXSkdHbGRDeEIwMUpaV2tqY1JEMnVkWWoxeGMrCnJWSENmSXNaUThlMUx3bU1RRytZZE83MlVoeW9LZlRVOER5b1h2WlNWb1VDVERsSzFBOEw1K0F2d1pHUlhuQ3QKZjZSK1BpOHhDaTJYdWRPZS9nSWtVV09MSWIwdEYvZFlKa2tZdExRYUpIVjFxNFhXbGlrWisvZnR0UDNIWk1URQpuWk51Z0FlV0svbkpFZzN0Mnc2YmsvYkVqNkJ2VElybThXSEhES1VuYUxmV0tleDhpdEx5dmoyV2oxT1pSKzFXCnk0TFMyOGQ1UUpoYUZNL3RtbzhTdElXcDlxZzM3eEVoSjk5aVpvQ0EwQT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K 8 | tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBeXExMExNajNHSi9nQm1Oekxrb052c1FHNUFtQ3JCRFREa1c5QlJEcldoZ3lnai90ClpTdlVmM2RMYVZ2T0hjaWxxbGpHSnFkT0hiUEg0ZldTNHR4UW5QR0tVMFpvY1MyUlB1cWsza0JKakRIY0NGd2YKM2NHUndpTHNLbjBDdGF4SkxiNWhkMUY3dXJiODZnV1Q3S3NYN3crRHNnSzJQRnJPWFJrWEdoUThuYysveDI5MApKRXd6d3dEcis0elUzaThHWmVXUXFDaXUyNUY1WE05djlYN2xqZUd0aTVnRWZtUlNpOStqYzY4UDBobVlqQUFjCjBwT25KWHdxV1NkN3M2UDZsdkd3dk1mL05BSGVwekNtU09wUjVhaWdhaERXNE5leE81ZU9vcmVoWFErK1BhQncKYXpNV3pDSEZHUnVMdmZ4a0ZieGVpNHhMQllEMDFaMWk5MEw1aFFJREFRQUJBb0lCQVFDOTRXbEE5L3AvaUhEaQpxMU5pbjZCbkE5SU0zRmdmQ2hnaGUvYU5nMzlyUmRZMEx0NGk5Y0E4dHkvZ2dsRUZtRkNVMmx5eUkvWk1YMzA1ClZkQUtXQ3Z5RFZ6eGpib1Zwb0k0TnE3RlJlZGh2K2lMc0h0dVQ0WldJayt0c3JiU0s1blhrRkJSNy9ZQ1JLT0kKUURlSTkvWVJVekNubW1EUEJLZm5rclVSQ3JxTGdVYWNmOHFzTmtoRGUzd1ZCUDRFdTYzSVhXd0VuSEhYVnZGWAp0VnRGUk1rMkE4RjJNWDJZa01QY3dZblNUMXE1Tzd3REthTC9uM3Z6T25uQU5Bd2RXRUVYbjIrZ3BueFY3a2h0CnNoY2JteHZZVU1XdWtWZ0ptUXkxUnEzdnVoRXBaNEVmakFzTXhkYXJlM1NtU05IWFlRU3JIZndUTW5QVnhyQWcKcjV2bTZNalZBb0dCQVBBaEVlbEY3eXdjMGg4SzBGNG92a204Y3hiODBld1VMSmJYc0hTNmI4R2FRRVhOSUJUSQpjUTlPQURONFBqU2JSVUx6aktFc0x5ekZrcDg0NDcwZlNRVk9SWHNnclR1OWdpUXQ4SnYvQzg2ZktPVWNFaVR6CkdxVld3R0F1aXFBRkFUKzRoYVVMczVncmdQVURjYnZHbHFuVmdoN0NiYzJaTVVRcTBRUFU3M3RyQW9HQkFOZ1MKdGdXSXBlYkthNmplVFlDREpETk5xeHlKUXBRdW1PRVRIT1IvQ3JHZEhFS2ZwZXdPM2N6OFVKeE14Z2VZYzNUSQpqalZnZ3JFTzVObEhqdkJyWW4rMHQ3UWJPT1Jicko2UEs4UFZuOEdzY0h6NFVSajF6VU9yNDNCU01kejFtdFRkClpvQXo2MTV6VW9vSitYTEZJWTZOODZGaUlhcTdSampBbEtQclpBclBBb0dBQ0xwSytsMk9XZDRhVFFLSm5FS0MKMkE4L1o2Qjh5TVhhOFFpWjQwUTdkNS94b2hmWWlLallZeVFFb2RwRytJYUVOL0MrTmNWeldYODgyd2lvVG1GcQp1QVNtUmRsa01uMnEwMEhRTXZ0TUpKQm9YaHR0RldhNG16WFIvQ3owNE9nTnFaRTlXa2hZbUxsTUVKdTFjSXZCClFoNytnYnV6WGZ1cGJMN1pwZmdCVkUwQ2dZQUlpRlNmeTFHaDE0U0EycVo4MkxEcFJidm9HSk9FZm9LVEFNbzMKUzcwRVhvdnJKWnJMdzVxR3FjQVZMQUwxOGRNOVhWNGdSWHRqdW83VzliaHpUZ3BKdUwwNFk0clBtYjhyVThRSwpxN2p2VVB2d00yNGdhalI4NDZETG9yTk5ZbldHeW1kdDBKOE96OGNHcEhZeFRnK1JMWkhkWVo2cXUxSitrenhMCmJOUTZpUUtCZ0RJQmVzTzFBQzhSMlBkRlVaV3J0bDc5OFYxNEd1RkMwdFR3K05SZmJ4TTFadXZVYlorSTg3Z00KOFROU3ZFS0VnbmN0NDNPRkFrMGNzY0s5cDcyTHJPNW55Q244MDJ5My9oMXRvM09BdkU0Y3hEVmlIWjNlLzBWZwpMcUJ5Q1M2MWQ1UFRnMXk0RG5vM054RnZzWDluS1RscUpQUzRlOGo1cndVV01aZCtWbWp5Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg== 9 | -------------------------------------------------------------------------------- /finaltest/solution/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | run: nginx 6 | name: nginx 7 | spec: 8 | type: NodePort 9 | ports: 10 | - port: 80 11 | protocol: TCP 12 | targetPort: 80 13 | name: http 14 | - port: 443 15 | protocol: TCP 16 | targetPort: 443 17 | name: https 18 | selector: 19 | run: nginx 20 | -------------------------------------------------------------------------------- /pingponredis/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: pingpodredis 5 | labels: 6 | name: pingpodredis 7 | spec: 8 | replicas: 1 9 | template: 10 | metadata: 11 | labels: 12 | name: pingpodredis 13 | spec: 14 | containers: 15 | - name: pingredis 16 | image: ipedrazas/pingpodredis 17 | ports: 18 | - containerPort: 8080 19 | env: 20 | - name: REDIS_HOST 21 | value: "localhost" 22 | - name: redis 23 | image: redis 24 | ports: 25 | - containerPort: 6379 26 | -------------------------------------------------------------------------------- /pingredis/ping-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: pingredis 5 | labels: 6 | name: pingredis 7 | spec: 8 | # if your cluster supports it, uncomment the following to automatically create 9 | # an external load-balanced IP for the frontend service. 10 | type: LoadBalancer 11 | ports: 12 | # the port that this service should serve on 13 | - port: 80 14 | targetPort: 8080 15 | selector: 16 | name: pingredis 17 | -------------------------------------------------------------------------------- /pingredis/pingredis-dep.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: pingredis 5 | labels: 6 | name: pingredis 7 | spec: 8 | replicas: 1 9 | template: 10 | metadata: 11 | labels: 12 | name: pingredis 13 | spec: 14 | containers: 15 | - name: pingredis 16 | image: ipedrazas/pingredis 17 | ports: 18 | - containerPort: 8080 19 | env: 20 | - name: REDIS_HOST 21 | value: "redis" 22 | -------------------------------------------------------------------------------- /pingredis/redis-dep.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: redis 5 | labels: 6 | name: redis 7 | spec: 8 | replicas: 1 9 | template: 10 | metadata: 11 | labels: 12 | name: redis 13 | spec: 14 | containers: 15 | - name: redis 16 | image: redis 17 | ports: 18 | - containerPort: 6379 19 | -------------------------------------------------------------------------------- /pingredis/redis-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: redis 5 | labels: 6 | name: redis 7 | spec: 8 | # type: LoadBalancer 9 | ports: 10 | # the port that this service should serve on 11 | - port: 6379 12 | targetPort: 6379 13 | selector: 14 | name: redis 15 | -------------------------------------------------------------------------------- /secrets/pod-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: optional-secret-env-pod 5 | spec: 6 | containers: 7 | - name: mycontainer 8 | image: redis 9 | env: 10 | - name: SUPER_SECRET 11 | valueFrom: 12 | secretKeyRef: 13 | name: mysupersecret 14 | key: supername 15 | # optional will make the pod to start even if the secret doesn't exist 16 | optional: true 17 | restartPolicy: Never 18 | -------------------------------------------------------------------------------- /secrets/secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: mysecret 5 | type: Opaque 6 | data: 7 | supername: aW1ub3R5b3VyZmF0aGVy 8 | password: cmV0dXJub2Z0aGVqZWRp 9 | --------------------------------------------------------------------------------