├── LICENSE ├── README.md ├── SECURITY.md ├── affinity ├── node-affinity.yaml ├── pod-affinity.yaml ├── pod-anti-affinity-5.yaml └── pod-anti-affinity.yaml ├── autoscaling └── hpa-example.yml ├── configmap ├── nginx-service.yml ├── nginx.yml └── reverseproxy.conf ├── dashboard ├── README.md └── sample-user.yaml ├── deployment ├── helloworld-healthcheck.yml ├── helloworld-liveness-readiness.yml ├── helloworld-nodeselector.yml ├── helloworld-secrets-volumes.yml ├── helloworld-secrets.yml └── helloworld.yml ├── docker-demo └── README.md ├── eks ├── README.md ├── amazonlinux-nonroot.yaml └── amazonlinux.yaml ├── elb-tls ├── helloworld-service.yml └── helloworld.yml ├── etcd └── README.md ├── external-dns ├── README.md ├── external-dns.yaml ├── ingress.yaml ├── put-node-policy.sh └── service-l4.yaml ├── first-app ├── helloworld-nodeport-service.yml ├── helloworld-service.yml └── helloworld.yml ├── flux └── README.md ├── helm ├── README.md ├── demo-chart │ ├── .gitignore │ ├── .helmignore │ ├── Chart.yaml │ ├── README.md │ ├── requirements.lock │ ├── requirements.yaml │ ├── templates │ │ ├── NOTES.txt │ │ ├── _helpers.tpl │ │ ├── deployment.yaml │ │ ├── ingress.yaml │ │ └── service.yaml │ └── values.yaml ├── helm-rbac.yaml ├── jenkins │ ├── Jenkinsfile.build │ ├── Jenkinsfile.deploy │ ├── README.md │ ├── jenkins-role-binding.yaml │ └── serviceaccount.yaml ├── put-bucket-policy.sh └── setup-s3-helm-repo.sh ├── ingress ├── echoservice.yml ├── helloworld-v1.yml ├── helloworld-v2.yml ├── ingress.yml └── nginx-ingress-controller.yml ├── istio ├── README.md ├── README.minikube.md ├── external-service.yaml ├── helloworld-gw.yaml ├── helloworld-jwt-enable.yaml ├── helloworld-jwt.yaml ├── helloworld-rbac-enable.yaml ├── helloworld-rbac.yaml ├── helloworld-tls-enable.yaml ├── helloworld-tls-legacy.yaml ├── helloworld-tls.yaml ├── helloworld-v2-canary.yaml ├── helloworld-v2-routing.yaml ├── helloworld-v2.yaml ├── helloworld-v3.yaml └── helloworld.yaml ├── kubeless ├── README.md ├── nginx-ingress-controller-with-elb.yml ├── node-example │ ├── example.js │ ├── package.json │ └── uppercase.js └── python-example │ └── example.py ├── metrics-server ├── auth-delegator.yaml ├── auth-reader.yaml ├── metrics-apiservice.yaml ├── metrics-server-deployment.yaml ├── metrics-server-service.yaml └── resource-reader.yaml ├── mutatingwebhook ├── Dockerfile ├── README.md ├── go.mod ├── main.go ├── pod.yaml ├── server.go ├── types.go └── webhook.yaml ├── pod-lifecycle └── lifecycle.yaml ├── pod-presets ├── README.md ├── deployments.yaml └── pod-presets.yaml ├── pod-security-policies ├── README.md ├── bad-pod.yml ├── good-pod.yml ├── initial-psp.yaml ├── restricted-psp.yaml └── serviceaccount.yml ├── postgres-operator ├── README.md ├── postgres-example-scale.yaml ├── postgres-example.yaml ├── quickstart.sh ├── set-path.sh └── storage.yml ├── replication-controller └── helloworld-repl-controller.yml ├── resourcequotas ├── defaults.yml ├── helloworld-no-quotas.yml ├── helloworld-with-quotas.yml └── resourcequota.yml ├── service-discovery ├── database-service.yml ├── database.yml ├── helloworld-db-service.yml ├── helloworld-db.yml └── secrets.yml ├── skaffold-demo ├── Dockerfile ├── go.mod ├── k8s-pod.yaml ├── main.go └── skaffold.yaml ├── statefulset └── cassandra.yaml ├── tolerations ├── README.md └── tolerations.yaml ├── users ├── README.md ├── admin-user.yaml └── user.yaml ├── volumes ├── README.md └── helloworld-with-volume.yml ├── wordpress-volumes ├── pv-claim.yml ├── storage.yml ├── wordpress-db-service.yml ├── wordpress-db.yml ├── wordpress-secrets.yml ├── wordpress-web-service.yml └── wordpress-web.yml └── wordpress ├── wordpress-secrets.yml ├── wordpress-service.yml └── wordpress-single-deployment-no-volumes.yml /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Edward Viaene 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 course 2 | This repository contains the course files for my Kubernetes course on Udemy: https://www.udemy.com/learn-devops-the-complete-kubernetes-course/?couponCode=KUBERNETES_GITHUB 3 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | This repository contains older docker images for demo purposes. Make sure to upgrade to the latest version if you want to use them. 6 | 7 | ## Reporting a Vulnerability 8 | 9 | Use GitHub issues or PRs to report a vulnerability. 10 | -------------------------------------------------------------------------------- /affinity/node-affinity.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: node-affinity 5 | spec: 6 | replicas: 3 7 | selector: 8 | matchLabels: 9 | app: node-affinity 10 | template: 11 | metadata: 12 | labels: 13 | app: node-affinity 14 | spec: 15 | affinity: 16 | nodeAffinity: 17 | requiredDuringSchedulingIgnoredDuringExecution: 18 | nodeSelectorTerms: 19 | - matchExpressions: 20 | - key: env 21 | operator: In 22 | values: 23 | - dev 24 | preferredDuringSchedulingIgnoredDuringExecution: 25 | - weight: 1 26 | preference: 27 | matchExpressions: 28 | - key: team 29 | operator: In 30 | values: 31 | - engineering-project1 32 | containers: 33 | - name: k8s-demo 34 | image: wardviaene/k8s-demo 35 | ports: 36 | - name: nodejs-port 37 | containerPort: 3000 38 | -------------------------------------------------------------------------------- /affinity/pod-affinity.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: pod-affinity-1 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: pod-affinity-1 10 | template: 11 | metadata: 12 | labels: 13 | app: pod-affinity-1 14 | spec: 15 | containers: 16 | - name: k8s-demo 17 | image: wardviaene/k8s-demo 18 | ports: 19 | - name: nodejs-port 20 | containerPort: 3000 21 | --- 22 | apiVersion: apps/v1 23 | kind: Deployment 24 | metadata: 25 | name: pod-affinity-2 26 | spec: 27 | replicas: 1 28 | selector: 29 | matchLabels: 30 | app: pod-affinity-2 31 | template: 32 | metadata: 33 | labels: 34 | app: pod-affinity-2 35 | spec: 36 | affinity: 37 | podAffinity: 38 | requiredDuringSchedulingIgnoredDuringExecution: 39 | - labelSelector: 40 | matchExpressions: 41 | - key: "app" 42 | operator: In 43 | values: 44 | - pod-affinity-1 45 | topologyKey: "kubernetes.io/hostname" 46 | containers: 47 | - name: redis 48 | image: redis 49 | ports: 50 | - name: redis-port 51 | containerPort: 6379 52 | -------------------------------------------------------------------------------- /affinity/pod-anti-affinity-5.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: pod-affinity-5 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: pod-affinity-5 10 | template: 11 | metadata: 12 | labels: 13 | app: pod-affinity-5 14 | spec: 15 | affinity: 16 | podAntiAffinity: 17 | preferredDuringSchedulingIgnoredDuringExecution: 18 | - weight: 100 19 | podAffinityTerm: 20 | labelSelector: 21 | matchExpressions: 22 | - key: "app" 23 | operator: In 24 | values: 25 | - pod-affinity-1 26 | - pod-affinity-3 27 | topologyKey: "kubernetes.io/hostname" 28 | containers: 29 | - name: k8s-demo 30 | image: wardviaene/k8s-demo 31 | ports: 32 | - name: nodejs-port 33 | containerPort: 3000 34 | --- 35 | -------------------------------------------------------------------------------- /affinity/pod-anti-affinity.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: pod-affinity-1 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: pod-affinity-1 10 | template: 11 | metadata: 12 | labels: 13 | app: pod-affinity-1 14 | spec: 15 | containers: 16 | - name: k8s-demo 17 | image: wardviaene/k8s-demo 18 | ports: 19 | - name: nodejs-port 20 | containerPort: 3000 21 | --- 22 | apiVersion: apps/v1 23 | kind: Deployment 24 | metadata: 25 | name: pod-affinity-2 26 | spec: 27 | replicas: 3 28 | selector: 29 | matchLabels: 30 | app: pod-affinity-2 31 | template: 32 | metadata: 33 | labels: 34 | app: pod-affinity-2 35 | spec: 36 | affinity: 37 | podAffinity: 38 | requiredDuringSchedulingIgnoredDuringExecution: 39 | - labelSelector: 40 | matchExpressions: 41 | - key: "app" 42 | operator: In 43 | values: 44 | - pod-affinity-1 45 | topologyKey: "kubernetes.io/hostname" 46 | containers: 47 | - name: redis 48 | image: redis 49 | ports: 50 | - name: redis-port 51 | containerPort: 6379 52 | --- 53 | apiVersion: apps/v1 54 | kind: Deployment 55 | metadata: 56 | name: pod-affinity-3 57 | spec: 58 | replicas: 3 59 | selector: 60 | matchLabels: 61 | app: pod-affinity-3 62 | template: 63 | metadata: 64 | labels: 65 | app: pod-affinity-3 66 | spec: 67 | affinity: 68 | podAntiAffinity: 69 | requiredDuringSchedulingIgnoredDuringExecution: 70 | - labelSelector: 71 | matchExpressions: 72 | - key: "app" 73 | operator: In 74 | values: 75 | - pod-affinity-1 76 | topologyKey: "kubernetes.io/hostname" 77 | containers: 78 | - name: k8s-demo 79 | image: wardviaene/k8s-demo 80 | ports: 81 | - name: nodejs-port 82 | containerPort: 3000 83 | --- 84 | apiVersion: apps/v1 85 | kind: Deployment 86 | metadata: 87 | name: pod-affinity-4 88 | spec: 89 | replicas: 1 90 | selector: 91 | matchLabels: 92 | app: pod-affinity-4 93 | template: 94 | metadata: 95 | labels: 96 | app: pod-affinity-4 97 | spec: 98 | affinity: 99 | podAntiAffinity: 100 | requiredDuringSchedulingIgnoredDuringExecution: 101 | - labelSelector: 102 | matchExpressions: 103 | - key: "app" 104 | operator: In 105 | values: 106 | - pod-affinity-1 107 | - pod-affinity-3 108 | topologyKey: "kubernetes.io/hostname" 109 | containers: 110 | - name: k8s-demo 111 | image: wardviaene/k8s-demo 112 | ports: 113 | - name: nodejs-port 114 | containerPort: 3000 115 | --- 116 | -------------------------------------------------------------------------------- /autoscaling/hpa-example.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: hpa-example 5 | spec: 6 | replicas: 3 7 | selector: 8 | matchLabels: 9 | app: hpa-example 10 | template: 11 | metadata: 12 | labels: 13 | app: hpa-example 14 | spec: 15 | containers: 16 | - name: hpa-example 17 | image: gcr.io/google_containers/hpa-example 18 | ports: 19 | - name: http-port 20 | containerPort: 80 21 | resources: 22 | requests: 23 | cpu: 200m 24 | --- 25 | apiVersion: v1 26 | kind: Service 27 | metadata: 28 | name: hpa-example 29 | spec: 30 | ports: 31 | - port: 31001 32 | nodePort: 31001 33 | targetPort: http-port 34 | protocol: TCP 35 | selector: 36 | app: hpa-example 37 | type: NodePort 38 | --- 39 | apiVersion: autoscaling/v1 40 | kind: HorizontalPodAutoscaler 41 | metadata: 42 | name: hpa-example-autoscaler 43 | spec: 44 | scaleTargetRef: 45 | apiVersion: apps/v1 46 | kind: Deployment 47 | name: hpa-example 48 | minReplicas: 1 49 | maxReplicas: 10 50 | targetCPUUtilizationPercentage: 50 51 | -------------------------------------------------------------------------------- /configmap/nginx-service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: helloworld-nginx-service 5 | spec: 6 | ports: 7 | - port: 80 8 | protocol: TCP 9 | selector: 10 | app: helloworld-nginx 11 | type: NodePort 12 | -------------------------------------------------------------------------------- /configmap/nginx.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: helloworld-nginx 5 | labels: 6 | app: helloworld-nginx 7 | spec: 8 | containers: 9 | - name: nginx 10 | image: nginx:1.11 11 | ports: 12 | - containerPort: 80 13 | volumeMounts: 14 | - name: config-volume 15 | mountPath: /etc/nginx/conf.d 16 | - name: k8s-demo 17 | image: wardviaene/k8s-demo 18 | ports: 19 | - containerPort: 3000 20 | volumes: 21 | - name: config-volume 22 | configMap: 23 | name: nginx-config 24 | items: 25 | - key: reverseproxy.conf 26 | path: reverseproxy.conf 27 | -------------------------------------------------------------------------------- /configmap/reverseproxy.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name localhost; 4 | 5 | location / { 6 | proxy_bind 127.0.0.1; 7 | proxy_pass http://127.0.0.1:3000; 8 | } 9 | 10 | error_page 500 502 503 504 /50x.html; 11 | location = /50x.html { 12 | root /usr/share/nginx/html; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /dashboard/README.md: -------------------------------------------------------------------------------- 1 | # Setting up the dashboard 2 | 3 | ## Start dashboard 4 | 5 | Create dashboard: 6 | ``` 7 | kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v1.10.1/src/deploy/recommended/kubernetes-dashboard.yaml 8 | ``` 9 | 10 | ## Create user 11 | 12 | Create sample user (if using RBAC - on by default on new installs with kops / kubeadm): 13 | ``` 14 | kubectl create -f sample-user.yaml 15 | 16 | ``` 17 | 18 | ## Get login token: 19 | ``` 20 | kubectl -n kube-system create token admin-user 21 | kubectl -n kube-system get secret | grep admin-user 22 | kubectl -n kube-system describe secret admin-user-token- 23 | ``` 24 | 25 | ## Login to dashboard 26 | Go to http://api.yourdomain.com:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/#!/login 27 | 28 | Login: admin 29 | Password: the password that is listed in ~/.kube/config (open file in editor and look for "password: ..." 30 | 31 | Choose for login token and enter the login token from the previous step 32 | -------------------------------------------------------------------------------- /dashboard/sample-user.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: admin-user 5 | namespace: kube-system 6 | --- 7 | apiVersion: rbac.authorization.k8s.io/v1 8 | kind: ClusterRoleBinding 9 | metadata: 10 | name: admin-user 11 | roleRef: 12 | apiGroup: rbac.authorization.k8s.io 13 | kind: ClusterRole 14 | name: cluster-admin 15 | subjects: 16 | - kind: ServiceAccount 17 | name: admin-user 18 | namespace: kube-system 19 | -------------------------------------------------------------------------------- /deployment/helloworld-healthcheck.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: helloworld-deployment 5 | spec: 6 | replicas: 3 7 | selector: 8 | matchLabels: 9 | app: helloworld 10 | template: 11 | metadata: 12 | labels: 13 | app: helloworld 14 | spec: 15 | containers: 16 | - name: k8s-demo 17 | image: wardviaene/k8s-demo 18 | ports: 19 | - name: nodejs-port 20 | containerPort: 3000 21 | livenessProbe: 22 | httpGet: 23 | path: / 24 | port: nodejs-port 25 | initialDelaySeconds: 15 26 | timeoutSeconds: 30 27 | -------------------------------------------------------------------------------- /deployment/helloworld-liveness-readiness.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: helloworld-readiness 5 | spec: 6 | replicas: 3 7 | selector: 8 | matchLabels: 9 | app: helloworld 10 | template: 11 | metadata: 12 | labels: 13 | app: helloworld 14 | spec: 15 | containers: 16 | - name: k8s-demo 17 | image: wardviaene/k8s-demo 18 | ports: 19 | - name: nodejs-port 20 | containerPort: 3000 21 | livenessProbe: 22 | httpGet: 23 | path: / 24 | port: nodejs-port 25 | initialDelaySeconds: 15 26 | timeoutSeconds: 30 27 | readinessProbe: 28 | httpGet: 29 | path: / 30 | port: nodejs-port 31 | initialDelaySeconds: 15 32 | timeoutSeconds: 30 33 | -------------------------------------------------------------------------------- /deployment/helloworld-nodeselector.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: helloworld-deployment 5 | spec: 6 | replicas: 3 7 | selector: 8 | matchLabels: 9 | app: helloworld 10 | template: 11 | metadata: 12 | labels: 13 | app: helloworld 14 | spec: 15 | containers: 16 | - name: k8s-demo 17 | image: wardviaene/k8s-demo 18 | ports: 19 | - name: nodejs-port 20 | containerPort: 3000 21 | nodeSelector: 22 | hardware: high-spec 23 | -------------------------------------------------------------------------------- /deployment/helloworld-secrets-volumes.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: helloworld-deployment 5 | spec: 6 | replicas: 3 7 | selector: 8 | matchLabels: 9 | app: helloworld 10 | template: 11 | metadata: 12 | labels: 13 | app: helloworld 14 | spec: 15 | containers: 16 | - name: k8s-demo 17 | image: wardviaene/k8s-demo 18 | ports: 19 | - name: nodejs-port 20 | containerPort: 3000 21 | volumeMounts: 22 | - name: cred-volume 23 | mountPath: /etc/creds 24 | readOnly: true 25 | volumes: 26 | - name: cred-volume 27 | secret: 28 | secretName: db-secrets 29 | -------------------------------------------------------------------------------- /deployment/helloworld-secrets.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: db-secrets 5 | type: Opaque 6 | data: 7 | username: cm9vdA== 8 | password: cGFzc3dvcmQ= 9 | -------------------------------------------------------------------------------- /deployment/helloworld.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: helloworld-deployment 5 | spec: 6 | replicas: 3 7 | selector: 8 | matchLabels: 9 | app: helloworld 10 | template: 11 | metadata: 12 | labels: 13 | app: helloworld 14 | spec: 15 | containers: 16 | - name: k8s-demo 17 | image: wardviaene/k8s-demo 18 | ports: 19 | - name: nodejs-port 20 | containerPort: 3000 21 | -------------------------------------------------------------------------------- /docker-demo/README.md: -------------------------------------------------------------------------------- 1 | # Docker demo 2 | Docker demo files can be found at https://github.com/wardviaene/docker-demo 3 | -------------------------------------------------------------------------------- /eks/README.md: -------------------------------------------------------------------------------- 1 | # Setup EKS 2 | ``` 3 | eksctl create cluster --name=cluster-2 --nodes=2 --region=eu-west-1 --managed 4 | ``` 5 | 6 | # Setup IAM Roles for Service Accounts 7 | 8 | Enable IAM Roles for Service Accounts on the EKS cluster 9 | 10 | ``` 11 | eksctl utils associate-iam-oidc-provider --cluster=cluster-2 12 | eksctl utils associate-iam-oidc-provider --cluster=cluster-2 --approve 13 | ``` 14 | 15 | Create new IAM Role using eksctl 16 | ``` 17 | eksctl create iamserviceaccount --cluster=cluster-2 --name=myserviceaccount --namespace=default --attach-policy-arn=arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess 18 | eksctl create iamserviceaccount --cluster=cluster-2 --name=myserviceaccount --namespace=default --attach-policy-arn=arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess --approve 19 | ``` 20 | -------------------------------------------------------------------------------- /eks/amazonlinux-nonroot.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: amazonlinux 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: amazonlinux 10 | template: 11 | metadata: 12 | labels: 13 | app: amazonlinux 14 | spec: 15 | serviceAccount: myserviceaccount 16 | securityContext: 17 | fsGroup: 1000 18 | runAsUser: 1000 19 | containers: 20 | - name: amazonlinux 21 | image: amazonlinux:2 22 | command: ["sleep", "infinity"] 23 | -------------------------------------------------------------------------------- /eks/amazonlinux.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: amazonlinux 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: amazonlinux 10 | template: 11 | metadata: 12 | labels: 13 | app: amazonlinux 14 | spec: 15 | serviceAccount: myserviceaccount 16 | containers: 17 | - name: amazonlinux 18 | image: amazonlinux:2 19 | command: ["sleep", "infinity"] 20 | -------------------------------------------------------------------------------- /elb-tls/helloworld-service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: helloworld-service 5 | annotations: 6 | service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:region:accountid:certificate/..." #replace this value 7 | service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "http" 8 | service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443" 9 | service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled: "true" 10 | service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout: "60" 11 | service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags: "environment=dev,app=helloworld" 12 | spec: 13 | ports: 14 | - name: http 15 | port: 80 16 | targetPort: nodejs-port 17 | protocol: TCP 18 | - name: https 19 | port: 443 20 | targetPort: nodejs-port 21 | protocol: TCP 22 | selector: 23 | app: helloworld 24 | type: LoadBalancer 25 | -------------------------------------------------------------------------------- /elb-tls/helloworld.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: helloworld-deployment 5 | spec: 6 | replicas: 3 7 | selector: 8 | matchLabels: 9 | app: helloworld 10 | template: 11 | metadata: 12 | labels: 13 | app: helloworld 14 | spec: 15 | containers: 16 | - name: k8s-demo 17 | image: wardviaene/k8s-demo 18 | ports: 19 | - name: nodejs-port 20 | containerPort: 3000 21 | -------------------------------------------------------------------------------- /etcd/README.md: -------------------------------------------------------------------------------- 1 | # etcd 2 | 3 | ## HA Cluster 4 | ``` 5 | kops create cluster --name=kubernetes.newtech.academy --state=s3://kops-state-b429b --zones eu-west-1a,eu-west-1b,eu-west-1c --master-zones eu-west-1a,eu-west-1b,eu-west-1c --node-count=3 --node-size=t2.micro --master-size=t2.micro --dns-zone=kubernetes.newtech.academy 6 | ``` 7 | 8 | ## Test backup 9 | Create an object (wait 15 min after creating the object to make sure it the backup ran) 10 | ``` 11 | kubectl create configmap readme --from-file=README.md 12 | ``` 13 | 14 | ## List backups 15 | bash is not available anymore in this container image, so make sure you use "sh" instead of "bash" 16 | ``` 17 | kubectl exec -it etcd-main -n kube-system -- sh 18 | ./etcd-manager-ctl -backup-store=s3://kops-state-b429b/kubernetes.newtech.academy/backups/etcd/main/ list-backups 19 | ``` 20 | -------------------------------------------------------------------------------- /external-dns/README.md: -------------------------------------------------------------------------------- 1 | # External DNS 2 | 3 | Project page: https://github.com/kubernetes-incubator/external-dns 4 | 5 | ## Create IAM Policy 6 | ``` 7 | ./put-node-policy.sh 8 | ``` 9 | 10 | ## start ingress 11 | ``` 12 | kubectl apply -f ../ingress/ 13 | ``` 14 | 15 | ## Create LoadBalancer for Ingress 16 | ``` 17 | kubectl apply -f service-l4.yaml 18 | ``` 19 | 20 | ## Configure kops 21 | 22 | Either turn off the Instance metadata service version 2, or enable IRSA (follow steps at https://github.com/kubernetes/kops/blob/master/docs/cluster_spec.md#service-account-issuer-discovery-and-aws-iam-roles-for-service-accounts-irsa). 23 | 24 | To disable the Instance Metadata service 2 (easiest option for non-production clusters), run kops edit instancegroup nodes-eu-west-1a --state=... and modify the instanceMetadata (do this for every zone): 25 | ``` 26 | spec: 27 | instanceMetadata: 28 | httpTokens: optional 29 | ``` 30 | 31 | If you want to use IRSA, this config can be used during kops edit cluster: 32 | ``` 33 | spec: 34 | # enable IRSA 35 | serviceAccountIssuerDiscovery: 36 | discoveryStore: s3://publicly-readable-store 37 | enableAWSOIDCProvider: true 38 | # IAM policy for service account with external-dns 39 | iam: 40 | serviceAccountExternalPermissions: 41 | - name: external-dns 42 | namespace: default 43 | aws: 44 | inlinePolicy: |- 45 | [ 46 | { 47 | "Effect": "Allow", 48 | "Action": ["route53:ListHostedZones", "route53:ListResourceRecordSets"], 49 | "Resource": "*" 50 | }, 51 | { 52 | "Effect": "Allow", 53 | "Action": [ 54 | "route53:ChangeResourceRecordSets" 55 | ], 56 | "Resource": [ 57 | "arn:aws:route53:::hostedzone/*" 58 | ] 59 | } 60 | ] 61 | ``` 62 | 63 | ## Create external DNS and ingress rules 64 | ``` 65 | kubectl apply -f external-dns.yaml 66 | kubectl apply -f ingress.yaml 67 | ``` 68 | -------------------------------------------------------------------------------- /external-dns/external-dns.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: external-dns 5 | --- 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: ClusterRole 8 | metadata: 9 | name: external-dns 10 | rules: 11 | - apiGroups: 12 | - "" 13 | resources: 14 | - services 15 | - endpoints 16 | - pods 17 | - nodes 18 | verbs: 19 | - get 20 | - list 21 | - watch 22 | - apiGroups: 23 | - extensions 24 | - "networking.k8s.io" # k8s 1.14+ 25 | resources: 26 | - ingresses 27 | verbs: 28 | - get 29 | - list 30 | - watch 31 | - apiGroups: 32 | - networking.istio.io 33 | resources: 34 | - gateways 35 | verbs: 36 | - get 37 | - list 38 | - watch 39 | - apiGroups: [""] 40 | resources: ["endpoints"] 41 | verbs: ["get","watch","list"] 42 | --- 43 | apiVersion: rbac.authorization.k8s.io/v1 44 | kind: ClusterRoleBinding 45 | metadata: 46 | name: external-dns-viewer 47 | roleRef: 48 | apiGroup: rbac.authorization.k8s.io 49 | kind: ClusterRole 50 | name: external-dns 51 | subjects: 52 | - kind: ServiceAccount 53 | name: external-dns 54 | namespace: default 55 | --- 56 | apiVersion: apps/v1 57 | kind: Deployment 58 | metadata: 59 | name: external-dns 60 | spec: 61 | selector: 62 | matchLabels: 63 | app: external-dns 64 | strategy: 65 | type: Recreate 66 | template: 67 | metadata: 68 | labels: 69 | app: external-dns 70 | spec: 71 | serviceAccountName: external-dns 72 | containers: 73 | - name: external-dns 74 | image: k8s.gcr.io/external-dns/external-dns:v0.10.1 75 | args: 76 | - --source=service 77 | - --source=ingress 78 | - --domain-filter=kubernetes.newtech.academy # will make ExternalDNS see only the hosted zones matching provided domain, omit to process all available hosted zones 79 | - --provider=aws 80 | - --policy=upsert-only # would prevent ExternalDNS from deleting any records, omit to enable full synchronization 81 | - --aws-zone-type=public # only look at public hosted zones (valid values are public, private or no value for both) 82 | - --registry=txt 83 | - --txt-owner-id=kubernetes.newtech.academy 84 | -------------------------------------------------------------------------------- /external-dns/ingress.yaml: -------------------------------------------------------------------------------- 1 | # An Ingress with 2 hosts and 3 endpoints 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: helloworld-rules 6 | annotations: 7 | kubernetes.io/ingress.class: k8s.io/ingress-nginx 8 | spec: 9 | rules: 10 | - host: helloworld-v1.kubernetes.newtech.academy 11 | http: 12 | paths: 13 | - path: / 14 | pathType: Prefix 15 | backend: 16 | service: 17 | name: helloworld-v1 18 | port: 19 | number: 80 20 | - host: helloworld-v2.kubernetes.newtech.academy 21 | http: 22 | paths: 23 | - path: / 24 | pathType: Prefix 25 | backend: 26 | service: 27 | name: helloworld-v2 28 | port: 29 | number: 80 30 | --- 31 | apiVersion: v1 32 | kind: ConfigMap 33 | metadata: 34 | name: ingress-nginx-controller 35 | data: 36 | use-proxy-protocol: "true" 37 | --- 38 | apiVersion: networking.k8s.io/v1 39 | kind: IngressClass 40 | metadata: 41 | name: ingress-nginx 42 | annotations: 43 | ingressclass.kubernetes.io/is-default-class: "true" 44 | spec: 45 | controller: k8s.io/ingress-nginx 46 | -------------------------------------------------------------------------------- /external-dns/put-node-policy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # This script adds permissions to the nodes IAM role, enabling any pod to use these AWS privileges 5 | # Usage of kube2iam is recommended, but not yet implemented by default in kops 6 | # 7 | 8 | DEFAULT_REGION="eu-west-1" 9 | AWS_REGION="${AWS_REGION:-${DEFAULT_REGION}}" 10 | 11 | NODE_ROLE="nodes.kubernetes.newtech.academy" 12 | 13 | export AWS_REGION 14 | 15 | aws iam put-role-policy --role-name ${NODE_ROLE} --policy-name external-dns-policy --policy-document '{ 16 | "Version": "2012-10-17", 17 | "Statement": [ 18 | { 19 | "Effect": "Allow", 20 | "Action": [ 21 | "route53:ChangeResourceRecordSets" 22 | ], 23 | "Resource": [ 24 | "arn:aws:route53:::hostedzone/*" 25 | ] 26 | }, 27 | { 28 | "Effect": "Allow", 29 | "Action": [ 30 | "route53:ListHostedZones", 31 | "route53:ListResourceRecordSets" 32 | ], 33 | "Resource": [ 34 | "*" 35 | ] 36 | } 37 | ] 38 | }' 39 | -------------------------------------------------------------------------------- /external-dns/service-l4.yaml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: ingress-nginx 5 | labels: 6 | app: ingress-nginx 7 | annotations: 8 | # Enable PROXY protocol 9 | service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: '*' 10 | # Increase the ELB idle timeout to avoid issues with WebSockets or Server-Sent Events. 11 | service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: '3600' 12 | # external-dns 13 | external-dns.alpha.kubernetes.io/hostname: ingress.kubernetes.newtech.academy 14 | spec: 15 | type: LoadBalancer 16 | selector: 17 | app: ingress-nginx 18 | ports: 19 | - name: http 20 | port: 80 21 | targetPort: http 22 | - name: https 23 | port: 443 24 | targetPort: https 25 | --- 26 | kind: ConfigMap 27 | apiVersion: v1 28 | metadata: 29 | name: nginx-configuration 30 | labels: 31 | app: ingress-nginx 32 | data: 33 | use-proxy-protocol: "true" 34 | -------------------------------------------------------------------------------- /first-app/helloworld-nodeport-service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: helloworld-service 5 | spec: 6 | ports: 7 | - port: 31001 8 | nodePort: 31001 9 | targetPort: nodejs-port 10 | protocol: TCP 11 | selector: 12 | app: helloworld 13 | type: NodePort 14 | -------------------------------------------------------------------------------- /first-app/helloworld-service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: helloworld-service 5 | spec: 6 | ports: 7 | - port: 80 8 | targetPort: nodejs-port 9 | protocol: TCP 10 | selector: 11 | app: helloworld 12 | type: LoadBalancer 13 | -------------------------------------------------------------------------------- /first-app/helloworld.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: nodehelloworld.example.com 5 | labels: 6 | app: helloworld 7 | spec: 8 | containers: 9 | - name: k8s-demo 10 | image: wardviaene/k8s-demo 11 | ports: 12 | - name: nodejs-port 13 | containerPort: 3000 14 | -------------------------------------------------------------------------------- /flux/README.md: -------------------------------------------------------------------------------- 1 | # Flux demo repository 2 | 3 | https://github.com/wardviaene/flux-demo 4 | 5 | # Installation 6 | 7 | ``` 8 | kubectl create ns flux 9 | export GHUSER="YOURUSER" 10 | fluxctl install \ 11 | --git-user=${GHUSER} \ 12 | --git-email=${GHUSER}@users.noreply.github.com \ 13 | --git-url=git@github.com:${GHUSER}/flux-demo \ 14 | --git-path=namespaces,workloads \ 15 | --namespace=flux | kubectl apply -f - 16 | ``` 17 | 18 | Check rollout status: 19 | ``` 20 | kubectl -n flux rollout status deployment/flux 21 | ``` 22 | 23 | # Setup SSH key 24 | ``` 25 | fluxctl identity --k8s-fwd-ns flux 26 | ``` 27 | 28 | # Sync repo manually 29 | ``` 30 | fluxctl sync --k8s-fwd-ns flux 31 | ``` 32 | -------------------------------------------------------------------------------- /helm/README.md: -------------------------------------------------------------------------------- 1 | # Helm 2 | 3 | ## Install helm 4 | ``` 5 | wget https://get.helm.sh/helm-v3.2.3-linux-amd64.tar.gz 6 | ``` 7 | 8 | Make sure to use the correct instructions below for the different helm versions. You can get the latest helm version from https://github.com/helm/helm/releases. If you want to install helm on Windows/MacOS then have a look at https://helm.sh/docs/intro/install/ for instructions. 9 | 10 | ## Initialize helm (helm >3.0) 11 | 12 | Starting from 3.0, tiller has been removed. There is no need to create a service account for tiller anymore. The only command that is mandatory is the helm repo add command below: 13 | 14 | ``` 15 | helm repo add stable https://kubernetes-charts.storage.googleapis.com/ 16 | ``` 17 | 18 | ## Setup S3 helm repository 19 | Make sure to set the default region in setup-s3-helm-repo.sh 20 | ``` 21 | ./setup-s3-helm-repo.sh 22 | ``` 23 | 24 | ## Package and push demo-chart 25 | 26 | ``` 27 | export AWS_REGION=yourregion # if not set in ~/.aws 28 | helm package demo-chart 29 | helm s3 push ./demo-chart-0.0.1.tgz my-charts 30 | ``` 31 | -------------------------------------------------------------------------------- /helm/demo-chart/.gitignore: -------------------------------------------------------------------------------- 1 | charts/* 2 | -------------------------------------------------------------------------------- /helm/demo-chart/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *~ 18 | # Various IDEs 19 | .project 20 | .idea/ 21 | *.tmproj 22 | -------------------------------------------------------------------------------- /helm/demo-chart/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | appVersion: "1.0" 3 | description: A Helm chart for Kubernetes 4 | name: demo-chart 5 | version: 0.0.1 6 | -------------------------------------------------------------------------------- /helm/demo-chart/README.md: -------------------------------------------------------------------------------- 1 | # Node demo app Chart 2 | 3 | ## Download dependencies 4 | ``` 5 | helm dependency update 6 | ``` 7 | 8 | ## Install Chart 9 | ``` 10 | helm install . 11 | ``` 12 | 13 | ## Upgrade Chart 14 | ``` 15 | helm upgrade --set image.tag=v0.0.2,mariadb.db.password=$DB_APP_PASS RELEASE . 16 | ``` 17 | -------------------------------------------------------------------------------- /helm/demo-chart/requirements.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: mariadb 3 | repository: https://charts.bitnami.com/bitnami 4 | version: 11.5.3 5 | digest: sha256:eac9933177811440c86ee4c0927b729b37025c86c176ae4e834badf2f41615db 6 | generated: "2023-03-12T16:12:25.885231-05:00" 7 | -------------------------------------------------------------------------------- /helm/demo-chart/requirements.yaml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: mariadb 3 | version: 11.x.x 4 | repository: https://charts.bitnami.com/bitnami 5 | condition: mariadb.enabled 6 | tags: 7 | - node-app-database 8 | -------------------------------------------------------------------------------- /helm/demo-chart/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Get the application URL by running these commands: 2 | {{- if .Values.ingress.enabled }} 3 | {{- range .Values.ingress.hosts }} 4 | http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }} 5 | {{- end }} 6 | {{- else if contains "NodePort" .Values.service.type }} 7 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "demo-chart.fullname" . }}) 8 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 9 | echo http://$NODE_IP:$NODE_PORT 10 | {{- else if contains "LoadBalancer" .Values.service.type }} 11 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 12 | You can watch the status of by running 'kubectl get svc -w {{ template "demo-chart.fullname" . }}' 13 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "demo-chart.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') 14 | echo http://$SERVICE_IP:{{ .Values.service.port }} 15 | {{- else if contains "ClusterIP" .Values.service.type }} 16 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "demo-chart.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") 17 | echo "Visit http://127.0.0.1:8080 to use your application" 18 | kubectl port-forward $POD_NAME 8080:80 19 | {{- end }} 20 | -------------------------------------------------------------------------------- /helm/demo-chart/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "demo-chart.name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 7 | {{- end -}} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 12 | If release name contains chart name it will be used as a full name. 13 | */}} 14 | {{- define "demo-chart.fullname" -}} 15 | {{- if .Values.fullnameOverride -}} 16 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} 17 | {{- else -}} 18 | {{- $name := default .Chart.Name .Values.nameOverride -}} 19 | {{- if contains $name .Release.Name -}} 20 | {{- .Release.Name | trunc 63 | trimSuffix "-" -}} 21 | {{- else -}} 22 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} 23 | {{- end -}} 24 | {{- end -}} 25 | {{- end -}} 26 | 27 | {{/* 28 | Create chart name and version as used by the chart label. 29 | */}} 30 | {{- define "demo-chart.chart" -}} 31 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} 32 | {{- end -}} 33 | 34 | {{/* 35 | Create a default fully qualified app name. 36 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 37 | */}} 38 | {{- define "mariadb.fullname" -}} 39 | {{- printf "%s-%s" .Release.Name "mariadb" | trunc 63 | trimSuffix "-" -}} 40 | {{- end -}} 41 | -------------------------------------------------------------------------------- /helm/demo-chart/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ template "demo-chart.fullname" . }} 5 | labels: 6 | app: {{ template "demo-chart.name" . }} 7 | chart: {{ template "demo-chart.chart" . }} 8 | release: {{ .Release.Name }} 9 | heritage: {{ .Release.Service }} 10 | spec: 11 | replicas: {{ .Values.replicaCount }} 12 | selector: 13 | matchLabels: 14 | app: {{ template "demo-chart.name" . }} 15 | release: {{ .Release.Name }} 16 | template: 17 | metadata: 18 | labels: 19 | app: {{ template "demo-chart.name" . }} 20 | release: {{ .Release.Name }} 21 | spec: 22 | containers: 23 | - name: {{ .Chart.Name }} 24 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 25 | imagePullPolicy: {{ .Values.image.pullPolicy }} 26 | ports: 27 | - name: http 28 | containerPort: 3000 29 | protocol: TCP 30 | env: 31 | - name: MYSQL_HOST 32 | {{- if .Values.mariadb.enabled }} 33 | value: {{ template "mariadb.fullname" . }} 34 | {{- else }} 35 | value: unknown 36 | {{- end }} 37 | - name: MYSQL_USER 38 | {{- if .Values.mariadb.enabled }} 39 | value: {{ .Values.mariadb.auth.username | quote }} 40 | {{- else }} 41 | value: unknown 42 | {{- end }} 43 | - name: MYSQL_DATABASE 44 | {{- if .Values.mariadb.enabled }} 45 | value: {{ .Values.mariadb.auth.database | quote }} 46 | {{- else }} 47 | value: unknown 48 | {{- end }} 49 | - name: MYSQL_PASSWORD 50 | valueFrom: 51 | secretKeyRef: 52 | {{- if .Values.mariadb.enabled }} 53 | name: {{ template "mariadb.fullname" . }} 54 | key: mariadb-password 55 | {{- else }} 56 | name: unknown 57 | key: db-password 58 | {{- end }} 59 | livenessProbe: 60 | httpGet: 61 | path: / 62 | port: http 63 | readinessProbe: 64 | httpGet: 65 | path: / 66 | port: http 67 | resources: 68 | {{ toYaml .Values.resources | indent 12 }} 69 | {{- with .Values.nodeSelector }} 70 | nodeSelector: 71 | {{ toYaml . | indent 8 }} 72 | {{- end }} 73 | {{- with .Values.affinity }} 74 | affinity: 75 | {{ toYaml . | indent 8 }} 76 | {{- end }} 77 | {{- with .Values.tolerations }} 78 | tolerations: 79 | {{ toYaml . | indent 8 }} 80 | {{- end }} 81 | -------------------------------------------------------------------------------- /helm/demo-chart/templates/ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.ingress.enabled -}} 2 | {{- $fullName := include "demo-chart.fullname" . -}} 3 | {{- $ingressPath := .Values.ingress.path -}} 4 | apiVersion: extensions/v1beta1 5 | kind: Ingress 6 | metadata: 7 | name: {{ $fullName }} 8 | labels: 9 | app: {{ template "demo-chart.name" . }} 10 | chart: {{ template "demo-chart.chart" . }} 11 | release: {{ .Release.Name }} 12 | heritage: {{ .Release.Service }} 13 | {{- with .Values.ingress.annotations }} 14 | annotations: 15 | {{ toYaml . | indent 4 }} 16 | {{- end }} 17 | spec: 18 | {{- if .Values.ingress.tls }} 19 | tls: 20 | {{- range .Values.ingress.tls }} 21 | - hosts: 22 | {{- range .hosts }} 23 | - {{ . }} 24 | {{- end }} 25 | secretName: {{ .secretName }} 26 | {{- end }} 27 | {{- end }} 28 | rules: 29 | {{- range .Values.ingress.hosts }} 30 | - host: {{ . }} 31 | http: 32 | paths: 33 | - path: {{ $ingressPath }} 34 | backend: 35 | serviceName: {{ $fullName }} 36 | servicePort: http 37 | {{- end }} 38 | {{- end }} 39 | -------------------------------------------------------------------------------- /helm/demo-chart/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ template "demo-chart.fullname" . }} 5 | labels: 6 | app: {{ template "demo-chart.name" . }} 7 | chart: {{ template "demo-chart.chart" . }} 8 | release: {{ .Release.Name }} 9 | heritage: {{ .Release.Service }} 10 | spec: 11 | type: {{ .Values.service.type }} 12 | ports: 13 | - port: {{ .Values.service.port }} 14 | targetPort: http 15 | protocol: TCP 16 | name: http 17 | selector: 18 | app: {{ template "demo-chart.name" . }} 19 | release: {{ .Release.Name }} 20 | -------------------------------------------------------------------------------- /helm/demo-chart/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for demo-chart. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | replicaCount: 3 6 | 7 | image: 8 | repository: wardviaene/node-demo-app 9 | tag: v0.0.1 10 | pullPolicy: IfNotPresent 11 | 12 | service: 13 | type: LoadBalancer 14 | port: 80 15 | 16 | ingress: 17 | enabled: false 18 | annotations: {} 19 | # kubernetes.io/ingress.class: nginx 20 | # kubernetes.io/tls-acme: "true" 21 | path: / 22 | hosts: 23 | - node-demo-app.newtech.academy 24 | tls: [] 25 | # - secretName: chart-example-tls 26 | # hosts: 27 | # - chart-example.local 28 | 29 | resources: {} 30 | # We usually recommend not to specify default resources and to leave this as a conscious 31 | # choice for the user. This also increases chances charts run on environments with little 32 | # resources, such as Minikube. If you do want to specify resources, uncomment the following 33 | # lines, adjust them as necessary, and remove the curly braces after 'resources:'. 34 | # limits: 35 | # cpu: 100m 36 | # memory: 128Mi 37 | # requests: 38 | # cpu: 100m 39 | # memory: 128Mi 40 | 41 | nodeSelector: {} 42 | 43 | tolerations: [] 44 | 45 | affinity: {} 46 | 47 | ## 48 | ## MariaDB chart configuration 49 | ## 50 | mariadb: 51 | enabled: true 52 | replication: 53 | enabled: false 54 | auth: 55 | database: app 56 | username: app-user 57 | master: 58 | persistence: 59 | enabled: true 60 | accessMode: ReadWriteOnce 61 | size: 8Gi 62 | 63 | -------------------------------------------------------------------------------- /helm/helm-rbac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: tiller 5 | namespace: kube-system 6 | --- 7 | apiVersion: rbac.authorization.k8s.io/v1beta1 8 | kind: ClusterRoleBinding 9 | metadata: 10 | name: tiller 11 | roleRef: 12 | apiGroup: rbac.authorization.k8s.io 13 | kind: ClusterRole 14 | name: cluster-admin 15 | subjects: 16 | - kind: ServiceAccount 17 | name: tiller 18 | namespace: kube-system 19 | -------------------------------------------------------------------------------- /helm/jenkins/Jenkinsfile.build: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent { 3 | kubernetes { 4 | label 'helm-pod' 5 | containerTemplate { 6 | name 'helm' 7 | image 'wardviaene/helm-s3' 8 | ttyEnabled true 9 | command 'cat' 10 | } 11 | } 12 | } 13 | stages { 14 | stage('Run helm') { 15 | steps { 16 | container('helm') { 17 | git url: 'git://github.com/wardviaene/kubernetes-course.git', branch: 'master' 18 | sh ''' 19 | HELM_BUCKET=helm-rytcufor 20 | PACKAGE=demo-chart 21 | export AWS_REGION=eu-west-1 22 | 23 | cp -r /home/helm/.helm ~ 24 | helm repo add my-charts s3://${HELM_BUCKET}/charts 25 | helm repo add stable https://kubernetes-charts.storage.googleapis.com 26 | helm repo list 27 | cd helm/${PACKAGE} 28 | helm dependency update 29 | helm package . 30 | helm s3 push --force ${PACKAGE}-*.tgz my-charts 31 | ''' 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /helm/jenkins/Jenkinsfile.deploy: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent { 3 | kubernetes { 4 | label 'helm-pod' 5 | serviceAccount 'jenkins-helm' 6 | containerTemplate { 7 | name 'helm-pod' 8 | image 'wardviaene/helm-s3' 9 | ttyEnabled true 10 | command 'cat' 11 | } 12 | } 13 | } 14 | stages { 15 | stage('Run helm') { 16 | steps { 17 | container('helm-pod') { 18 | git url: 'git://github.com/wardviaene/kubernetes-course.git', branch: 'master' 19 | sh ''' 20 | HELM_BUCKET=helm-rytcufor 21 | PACKAGE=demo-chart 22 | export AWS_REGION=eu-west-1 23 | 24 | cp -r /home/helm/.helm ~ 25 | helm repo add my-charts s3://${HELM_BUCKET}/charts 26 | DEPLOYED=$(helm list |grep -E "^${PACKAGE}" |grep DEPLOYED |wc -l) 27 | if [ $DEPLOYED == 0 ] ; then 28 | helm install --name ${PACKAGE} my-charts/${PACKAGE} 29 | else 30 | helm upgrade ${PACKAGE} my-charts/${PACKAGE} 31 | fi 32 | echo "deployed!" 33 | ''' 34 | } 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /helm/jenkins/README.md: -------------------------------------------------------------------------------- 1 | # install jenkins 2 | ``` 3 | kubectl create -f serviceaccount.yaml 4 | helm install jenkins --set rbac.create=true,master.runAsUser=1000,master.fsGroup=1000,agent.enabled=true bitnami/jenkins 5 | helm create -f jenkins-role-binding.yaml 6 | kubectl patch svc jenkins --type merge -p '{"spec":{"ports": [{"port": 50000,"name":"agent-listener", "protocol": "TCP", "targetPort": "agent-listener"}, {"port": 80, "name": "http", "targetPort": "http"}]}}' 7 | ``` 8 | 9 | # Plugins 10 | Ensure you install the following plugins within jenkins: 11 | * Pipelines 12 | * Kubernetes 13 | * Git 14 | 15 | To configure the Kubernetes plugin correctly, navigate to Manage Jenkins -> Manage Nodes and Clouds -> Configure Clouds -> Add a new cloud. The name should be pre-filled with "kubernetes". Fill out http://jenkins as Jenkins URL in the "Kubernetes Cloud details" and click "Save" without filling out anything extra. The Kubernetes plugin will now automatically find the Kubernetes cluster jenkins is installed on. 16 | 17 | If you get a timeout on port 50000 then go to "Manage Jenkins" -> "Configure Global Security" -> under "Agents" check whether TCP port for inbound agents is set to "Fixed" 50000. 18 | 19 | Note: ensure that you are running jenkins privately (non-internet facing), as port 50000 will also be exposed in this setup. 20 | -------------------------------------------------------------------------------- /helm/jenkins/jenkins-role-binding.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: Role 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | metadata: 5 | name: jenkins 6 | rules: 7 | - apiGroups: [""] 8 | resources: ["pods"] 9 | verbs: ["create","delete","get","list","patch","update","watch"] 10 | - apiGroups: [""] 11 | resources: ["pods/exec"] 12 | verbs: ["create","delete","get","list","patch","update","watch"] 13 | - apiGroups: [""] 14 | resources: ["pods/log"] 15 | verbs: ["get","list","watch"] 16 | - apiGroups: [""] 17 | resources: ["events"] 18 | verbs: ["watch"] 19 | - apiGroups: [""] 20 | resources: ["secrets"] 21 | verbs: ["get"] 22 | 23 | --- 24 | apiVersion: rbac.authorization.k8s.io/v1 25 | kind: RoleBinding 26 | metadata: 27 | name: jenkins 28 | roleRef: 29 | apiGroup: rbac.authorization.k8s.io 30 | kind: Role 31 | name: jenkins 32 | subjects: 33 | - kind: ServiceAccount 34 | name: jenkins 35 | -------------------------------------------------------------------------------- /helm/jenkins/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: jenkins-helm 5 | --- 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: ClusterRoleBinding 8 | metadata: 9 | name: jenkins-helm 10 | roleRef: 11 | apiGroup: rbac.authorization.k8s.io 12 | kind: ClusterRole 13 | name: cluster-admin 14 | subjects: 15 | - kind: ServiceAccount 16 | name: jenkins-helm 17 | namespace: default 18 | -------------------------------------------------------------------------------- /helm/put-bucket-policy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | DEFAULT_REGION="eu-west-1" 3 | AWS_REGION="${AWS_REGION:-${DEFAULT_REGION}}" 4 | 5 | BUCKET="helm-rytcufor" 6 | NODE_ROLE_ARN="arn:aws:iam::*" 7 | 8 | export AWS_REGION 9 | 10 | aws s3api put-bucket-policy --bucket ${BUCKET} --policy '{ 11 | "Statement": [ 12 | { 13 | "Effect": "Allow", 14 | "Principal": { 15 | "AWS": "'${NODE_ROLE_ARN}'" 16 | }, 17 | "Action": [ 18 | "s3:GetObject", 19 | "s3:PutObject" 20 | ], 21 | "Resource": "arn:aws:s3:::'${BUCKET}'/*" 22 | }, 23 | { 24 | "Effect": "Allow", 25 | "Principal": { 26 | "AWS": "'${NODE_ROLE_ARN}'" 27 | }, 28 | "Action": "s3:ListBucket", 29 | "Resource": "arn:aws:s3:::'${BUCKET}'" 30 | } 31 | ] 32 | }' 33 | -------------------------------------------------------------------------------- /helm/setup-s3-helm-repo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # create random string 6 | RANDOM_STRING=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | tr '[:upper:]' '[:lower:]' | head -n 1) 7 | 8 | # it's important to set the AWS_REGION if not set. Change the default 9 | DEFAULT_REGION="eu-west-1" 10 | AWS_REGION="${AWS_REGION:-${DEFAULT_REGION}}" 11 | 12 | export AWS_REGION 13 | 14 | # create s3 bucket 15 | if [ "$AWS_REGION" == "us-east-1" ] ; then 16 | aws s3api create-bucket --bucket helm-${RANDOM_STRING} 17 | else 18 | aws s3api create-bucket --bucket helm-${RANDOM_STRING} --region $AWS_REGION --create-bucket-configuration LocationConstraint=${AWS_REGION} 19 | fi 20 | 21 | # install helm s3 plugin 22 | helm plugin install https://github.com/hypnoglow/helm-s3.git 23 | 24 | # initialize s3 bucket 25 | helm s3 init s3://helm-${RANDOM_STRING}/charts 26 | 27 | # add repository to helm 28 | helm repo add my-charts s3://helm-${RANDOM_STRING}/charts 29 | -------------------------------------------------------------------------------- /ingress/echoservice.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ReplicationController 3 | metadata: 4 | name: echoheaders 5 | spec: 6 | replicas: 1 7 | template: 8 | metadata: 9 | labels: 10 | app: echoheaders 11 | spec: 12 | containers: 13 | - name: echoheaders 14 | image: gcr.io/google_containers/echoserver:1.0 15 | ports: 16 | - containerPort: 8080 17 | --- 18 | apiVersion: v1 19 | kind: Service 20 | metadata: 21 | name: echoheaders-default 22 | labels: 23 | app: echoheaders 24 | spec: 25 | type: NodePort 26 | ports: 27 | - port: 80 28 | nodePort: 30302 29 | targetPort: 8080 30 | protocol: TCP 31 | name: http 32 | selector: 33 | app: echoheaders 34 | -------------------------------------------------------------------------------- /ingress/helloworld-v1.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: helloworld-v1-deployment 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: helloworld-v1 10 | template: 11 | metadata: 12 | labels: 13 | app: helloworld-v1 14 | spec: 15 | containers: 16 | - name: k8s-demo 17 | image: wardviaene/k8s-demo:latest 18 | ports: 19 | - name: nodejs-port 20 | containerPort: 3000 21 | --- 22 | apiVersion: v1 23 | kind: Service 24 | metadata: 25 | name: helloworld-v1 26 | spec: 27 | type: NodePort 28 | ports: 29 | - port: 80 30 | nodePort: 30303 31 | targetPort: 3000 32 | protocol: TCP 33 | name: http 34 | selector: 35 | app: helloworld-v1 36 | -------------------------------------------------------------------------------- /ingress/helloworld-v2.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: helloworld-v2-deployment 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: helloworld-v2 10 | template: 11 | metadata: 12 | labels: 13 | app: helloworld-v2 14 | spec: 15 | containers: 16 | - name: k8s-demo 17 | image: wardviaene/k8s-demo:2 18 | ports: 19 | - name: nodejs-port 20 | containerPort: 3000 21 | --- 22 | apiVersion: v1 23 | kind: Service 24 | metadata: 25 | name: helloworld-v2 26 | spec: 27 | type: NodePort 28 | ports: 29 | - port: 80 30 | nodePort: 30304 31 | targetPort: 3000 32 | protocol: TCP 33 | name: http 34 | selector: 35 | app: helloworld-v2 36 | -------------------------------------------------------------------------------- /ingress/ingress.yml: -------------------------------------------------------------------------------- 1 | # An Ingress with 2 hosts and 3 endpoints 2 | apiVersion: networking.k8s.io/v1 3 | kind: Ingress 4 | metadata: 5 | name: helloworld-rules 6 | spec: 7 | #To specify a default backend, uncomment the following lines: 8 | #defaultBackend: 9 | # service: 10 | # name: echoheaders-default 11 | # port: 12 | # number: 80 13 | rules: 14 | - host: helloworld-v1.example.com 15 | http: 16 | paths: 17 | - path: / 18 | pathType: Prefix 19 | backend: 20 | service: 21 | name: helloworld-v1 22 | port: 23 | number: 80 24 | - host: helloworld-v2.example.com 25 | http: 26 | paths: 27 | - path: / 28 | pathType: Prefix 29 | backend: 30 | service: 31 | name: helloworld-v2 32 | port: 33 | number: 80 34 | -------------------------------------------------------------------------------- /ingress/nginx-ingress-controller.yml: -------------------------------------------------------------------------------- 1 | # updated this file with the latest ingress-controller from https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml 2 | apiVersion: apps/v1 3 | kind: DaemonSet 4 | metadata: 5 | name: nginx-ingress-controller 6 | spec: 7 | selector: 8 | matchLabels: 9 | app: ingress-nginx 10 | template: 11 | metadata: 12 | labels: 13 | app: ingress-nginx 14 | spec: 15 | serviceAccountName: nginx-ingress-serviceaccount 16 | containers: 17 | - name: nginx-ingress-controller 18 | image: k8s.gcr.io/ingress-nginx/controller:v1.1.0@sha256:f766669fdcf3dc26347ed273a55e754b427eb4411ee075a53f30718b4499076a 19 | lifecycle: 20 | preStop: 21 | exec: 22 | command: 23 | - /wait-shutdown 24 | args: 25 | - /nginx-ingress-controller 26 | - --election-id=ingress-controller-leader 27 | - --controller-class=k8s.io/ingress-nginx 28 | - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller 29 | - --validating-webhook=:8443 30 | - --validating-webhook-certificate=/usr/local/certificates/cert 31 | - --validating-webhook-key=/usr/local/certificates/key 32 | securityContext: 33 | capabilities: 34 | drop: 35 | - ALL 36 | add: 37 | - NET_BIND_SERVICE 38 | # www-data -> 101 39 | runAsUser: 101 40 | env: 41 | - name: POD_NAME 42 | valueFrom: 43 | fieldRef: 44 | fieldPath: metadata.name 45 | - name: POD_NAMESPACE 46 | valueFrom: 47 | fieldRef: 48 | fieldPath: metadata.namespace 49 | ports: 50 | - name: http 51 | containerPort: 80 52 | hostPort: 80 53 | - name: https 54 | containerPort: 443 55 | hostPort: 443 56 | livenessProbe: 57 | failureThreshold: 5 58 | httpGet: 59 | path: /healthz 60 | port: 10254 61 | scheme: HTTP 62 | initialDelaySeconds: 10 63 | periodSeconds: 10 64 | successThreshold: 1 65 | timeoutSeconds: 1 66 | readinessProbe: 67 | failureThreshold: 3 68 | httpGet: 69 | path: /healthz 70 | port: 10254 71 | scheme: HTTP 72 | initialDelaySeconds: 10 73 | periodSeconds: 10 74 | successThreshold: 1 75 | timeoutSeconds: 1 76 | --- 77 | kind: ConfigMap 78 | apiVersion: v1 79 | metadata: 80 | name: nginx-configuration 81 | labels: 82 | app: ingress-nginx 83 | --- 84 | kind: ConfigMap 85 | apiVersion: v1 86 | metadata: 87 | name: tcp-services 88 | --- 89 | kind: ConfigMap 90 | apiVersion: v1 91 | metadata: 92 | name: udp-services 93 | --- 94 | apiVersion: v1 95 | kind: ServiceAccount 96 | metadata: 97 | name: nginx-ingress-serviceaccount 98 | 99 | --- 100 | 101 | apiVersion: rbac.authorization.k8s.io/v1 102 | kind: ClusterRole 103 | metadata: 104 | name: nginx-ingress-clusterrole 105 | rules: 106 | - apiGroups: 107 | - "" 108 | resources: 109 | - configmaps 110 | - endpoints 111 | - nodes 112 | - pods 113 | - secrets 114 | verbs: 115 | - list 116 | - watch 117 | - apiGroups: 118 | - "" 119 | resources: 120 | - nodes 121 | verbs: 122 | - get 123 | - apiGroups: 124 | - "" 125 | resources: 126 | - services 127 | verbs: 128 | - get 129 | - list 130 | - watch 131 | - apiGroups: 132 | - "extensions" 133 | - "networking.k8s.io" 134 | resources: 135 | - ingresses 136 | - ingressclasses 137 | verbs: 138 | - get 139 | - list 140 | - watch 141 | - apiGroups: 142 | - "" 143 | resources: 144 | - events 145 | verbs: 146 | - create 147 | - patch 148 | - apiGroups: 149 | - "extensions" 150 | - "networking.k8s.io" 151 | resources: 152 | - ingresses/status 153 | verbs: 154 | - update 155 | - apiGroups: 156 | - '' 157 | resources: 158 | - configmaps 159 | resourceNames: 160 | - ingress-controller-leader 161 | verbs: 162 | - get 163 | - update 164 | - apiGroups: 165 | - '' 166 | resources: 167 | - configmaps 168 | verbs: 169 | - create 170 | - apiGroups: 171 | - '' 172 | resources: 173 | - events 174 | verbs: 175 | - create 176 | - patch 177 | --- 178 | apiVersion: rbac.authorization.k8s.io/v1 179 | kind: Role 180 | metadata: 181 | name: nginx-ingress-role 182 | rules: 183 | - apiGroups: 184 | - "" 185 | resources: 186 | - configmaps 187 | - pods 188 | - secrets 189 | - namespaces 190 | verbs: 191 | - get 192 | - apiGroups: 193 | - "" 194 | resources: 195 | - configmaps 196 | resourceNames: 197 | # Defaults to "-" 198 | # Here: "-" 199 | # This has to be adapted if you change either parameter 200 | # when launching the nginx-ingress-controller. 201 | - "ingress-controller-leader-nginx" 202 | verbs: 203 | - get 204 | - update 205 | - apiGroups: 206 | - "" 207 | resources: 208 | - configmaps 209 | verbs: 210 | - create 211 | - apiGroups: 212 | - "" 213 | resources: 214 | - endpoints 215 | verbs: 216 | - get 217 | --- 218 | apiVersion: rbac.authorization.k8s.io/v1 219 | kind: RoleBinding 220 | metadata: 221 | name: nginx-ingress-role-nisa-binding 222 | roleRef: 223 | apiGroup: rbac.authorization.k8s.io 224 | kind: Role 225 | name: nginx-ingress-role 226 | subjects: 227 | - kind: ServiceAccount 228 | name: nginx-ingress-serviceaccount 229 | 230 | --- 231 | apiVersion: rbac.authorization.k8s.io/v1 232 | kind: ClusterRoleBinding 233 | metadata: 234 | name: nginx-ingress-clusterrole-nisa-binding 235 | roleRef: 236 | apiGroup: rbac.authorization.k8s.io 237 | kind: ClusterRole 238 | name: nginx-ingress-clusterrole 239 | subjects: 240 | - kind: ServiceAccount 241 | name: nginx-ingress-serviceaccount 242 | namespace: default 243 | --- 244 | # Source: ingress-nginx/templates/controller-service-webhook.yaml 245 | apiVersion: v1 246 | kind: Service 247 | metadata: 248 | labels: 249 | helm.sh/chart: ingress-nginx-3.10.1 250 | app.kubernetes.io/name: ingress-nginx 251 | app.kubernetes.io/instance: ingress-nginx 252 | app.kubernetes.io/version: 0.41.2 253 | app.kubernetes.io/managed-by: Helm 254 | app.kubernetes.io/component: controller 255 | name: ingress-nginx-controller-admission 256 | spec: 257 | type: ClusterIP 258 | ports: 259 | - name: https-webhook 260 | port: 443 261 | targetPort: webhook 262 | selector: 263 | app: ingress-nginx 264 | --- 265 | # Source: ingress-nginx/templates/controller-service.yaml 266 | apiVersion: v1 267 | kind: Service 268 | metadata: 269 | annotations: 270 | labels: 271 | helm.sh/chart: ingress-nginx-3.10.1 272 | app.kubernetes.io/name: ingress-nginx 273 | app.kubernetes.io/instance: ingress-nginx 274 | app.kubernetes.io/version: 0.41.2 275 | app.kubernetes.io/managed-by: Helm 276 | app.kubernetes.io/component: controller 277 | name: ingress-nginx 278 | spec: 279 | type: NodePort 280 | ports: 281 | - name: http 282 | port: 80 283 | protocol: TCP 284 | targetPort: http 285 | - name: https 286 | port: 443 287 | protocol: TCP 288 | targetPort: https 289 | selector: 290 | app: ingress-nginx 291 | --- 292 | -------------------------------------------------------------------------------- /istio/README.md: -------------------------------------------------------------------------------- 1 | # istio 2 | 3 | ## Kops configuration 4 | ``` 5 | kops edit cluster kubernetes.newtech.academy 6 | ``` 7 | Add: 8 | ``` 9 | kubeAPIServer: 10 | admissionControl: 11 | - NamespaceLifecycle 12 | - LimitRanger 13 | - ServiceAccount 14 | - PersistentVolumeLabel 15 | - DefaultStorageClass 16 | - DefaultTolerationSeconds 17 | - MutatingAdmissionWebhook 18 | - ValidatingAdmissionWebhook 19 | - ResourceQuota 20 | - NodeRestriction 21 | - Priority 22 | ``` 23 | 24 | ## download (1.0.3): 25 | ``` 26 | cd ~ 27 | wget https://github.com/istio/istio/releases/download/1.0.3/istio-1.0.3-linux.tar.gz 28 | tar -xzvf istio-1.0.3-linux.tar.gz 29 | cd istio-1.0.3 30 | echo 'export PATH="$PATH:/home/ubuntu/istio-1.0.3/bin"' >> ~/.profile 31 | ``` 32 | 33 | ## Download (latest): 34 | ``` 35 | cd ~ 36 | curl -L https://git.io/getLatestIstio | sh - 37 | echo 'export PATH="$PATH:/home/ubuntu/istio-1.0.3/bin"' >> ~/.profile # change 1.0.3 in your version 38 | cd istio-1.0.3 # change 1.0.3 in your version 39 | ``` 40 | 41 | ## Istio install 42 | 43 | Apply CRDs: 44 | 45 | ``` 46 | kubectl apply -f ~/istio-1.0.3/install/kubernetes/helm/istio/templates/crds.yaml 47 | ``` 48 | 49 | Wait a few seconds. 50 | 51 | 52 | Option 1: with no mutual TLS authentication 53 | ``` 54 | kubectl apply -f ~/istio-1.0.3/install/kubernetes/istio-demo.yaml 55 | ``` 56 | 57 | Option 2: or with mutual TLS authentication 58 | ``` 59 | kubectl apply -f ~/istio-1.0.3/install/kubernetes/istio-demo-auth.yaml 60 | ``` 61 | 62 | ## Example app 63 | 64 | ### Example app (from istio) 65 | ``` 66 | export PATH="$PATH:/home/ubuntu/istio-1.0.3/bin" 67 | kubectl apply -f <(istioctl kube-inject -f samples/bookinfo/platform/kube/bookinfo.yaml) 68 | ``` 69 | 70 | ### Hello world app 71 | ``` 72 | export PATH="$PATH:/home/ubuntu/istio-1.0.3/bin" 73 | kubectl apply -f <(istioctl kube-inject -f helloworld.yaml) 74 | kubectl apply -f helloworld-gw.yaml 75 | ``` 76 | 77 | ### Mutual TLS example 78 | Create pods, services, destinationrules, virtualservices 79 | ``` 80 | kubectl create -f <(istioctl kube-inject -f helloworld-tls.yaml) 81 | kubectl create -f helloworld-legacy.yaml 82 | ``` 83 | 84 | ### End-user authentication 85 | ``` 86 | kubectl create -f <(istioctl kube-inject -f helloworld-jwt.yaml) 87 | kubectl create -f helloworld-jwt-enable.yaml 88 | ``` 89 | -------------------------------------------------------------------------------- /istio/README.minikube.md: -------------------------------------------------------------------------------- 1 | # istio 2 | 3 | ## Launch minikube 4 | 5 | * Install the latest release of minikube: https://github.com/kubernetes/minikube 6 | 7 | ``` 8 | minikube start --memory=8192 --cpus=4 --kubernetes-version=v1.10.0 --vm-driver=`your_vm_driver_choice` 9 | ``` 10 | 11 | 12 | ## download (1.0.3): 13 | ``` 14 | cd ~ 15 | wget https://github.com/istio/istio/releases/download/1.0.3/istio-1.0.3-linux.tar.gz # linux 16 | wget https://github.com/istio/istio/releases/download/1.0.3/istio-1.0.3-osx.tar.gz # macos 17 | tar -xzvf istio-1.0.3-linux.tar.gz 18 | cd istio-1.0.3 19 | echo 'export PATH="$PATH:~/istio-1.0.3/bin"' >> ~/.profile 20 | ``` 21 | 22 | ## Download (latest): 23 | ``` 24 | cd ~ 25 | curl -L https://git.io/getLatestIstio | sh - 26 | echo 'export PATH="$PATH:~/istio-1.0.3/bin"' >> ~/.profile # change 1.0.3 in your version 27 | cd istio-1.0.3 # change 1.0.3 in your version 28 | ``` 29 | 30 | ## Istio install 31 | 32 | Apply CRDs: 33 | 34 | ``` 35 | kubectl apply -f ~/istio-1.0.3/install/kubernetes/helm/istio/templates/crds.yaml 36 | ``` 37 | 38 | Wait a few seconds. 39 | 40 | 41 | Option 1: with no mutual TLS authentication (the next demos assume no mutual TLS) 42 | ``` 43 | kubectl apply -f ~/istio-1.0.3/install/kubernetes/istio-demo.yaml 44 | ``` 45 | 46 | Option 2: or with mutual TLS authentication 47 | ``` 48 | kubectl apply -f ~/istio-1.0.3/install/kubernetes/istio-demo-auth.yaml 49 | ``` 50 | 51 | ## Disable LoadBalancer 52 | 53 | Replace LoadBalancer in NodePort with: 54 | 55 | ``` 56 | kubectl edit -n istio-system svc/istio-ingressgateway 57 | ``` 58 | 59 | Get the URL with: 60 | ``` 61 | minikube service istio-ingressgateway -n istio-system --url 62 | ``` 63 | 64 | ## Example app 65 | 66 | ### Example app (from istio) 67 | ``` 68 | export PATH="$PATH:~/istio-1.0.3/bin" 69 | kubectl apply -f <(istioctl kube-inject -f samples/bookinfo/platform/kube/bookinfo.yaml) 70 | ``` 71 | 72 | ### Hello world app 73 | ``` 74 | export PATH="$PATH:~/istio-1.0.3/bin" 75 | wget https://raw.githubusercontent.com/wardviaene/kubernetes-course/master/istio/helloworld.yaml 76 | kubectl apply -f <(istioctl kube-inject -f helloworld.yaml) 77 | kubectl apply -f https://raw.githubusercontent.com/wardviaene/kubernetes-course/master/istio/helloworld-gw.yaml 78 | ``` 79 | 80 | ### Mutual TLS example 81 | Create pods, services, destinationrules, virtualservices 82 | ``` 83 | wget https://raw.githubusercontent.com/wardviaene/kubernetes-course/master/istio/helloworld-tls.yaml 84 | kubectl create -f <(istioctl kube-inject -f helloworld-tls.yaml) 85 | kubectl create -f https://raw.githubusercontent.com/wardviaene/kubernetes-course/master/istio/helloworld-legacy.yaml 86 | ``` 87 | 88 | ### End-user authentication 89 | ``` 90 | wget https://raw.githubusercontent.com/wardviaene/kubernetes-course/master/istio/helloworld-jwt.yaml 91 | kubectl create -f <(istioctl kube-inject -f helloworld-jwt.yaml) 92 | kubectl create -f https://raw.githubusercontent.com/wardviaene/kubernetes-course/master/istio/helloworld-jwt-enable.yaml 93 | ``` 94 | -------------------------------------------------------------------------------- /istio/external-service.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # http 3 | # 4 | apiVersion: networking.istio.io/v1alpha3 5 | kind: ServiceEntry 6 | metadata: 7 | name: ifconfig-co-http 8 | spec: 9 | hosts: 10 | - ifconfig.co 11 | ports: 12 | - number: 80 13 | name: http 14 | protocol: HTTP 15 | resolution: DNS 16 | location: MESH_EXTERNAL 17 | --- 18 | # 19 | # https 20 | # 21 | apiVersion: networking.istio.io/v1alpha3 22 | kind: ServiceEntry 23 | metadata: 24 | name: ifconfig-co-https 25 | spec: 26 | hosts: 27 | - ifconfig.co 28 | ports: 29 | - number: 443 30 | name: https 31 | protocol: HTTPS 32 | resolution: DNS 33 | location: MESH_EXTERNAL 34 | --- 35 | apiVersion: networking.istio.io/v1alpha3 36 | kind: VirtualService 37 | metadata: 38 | name: ifconfig-co 39 | spec: 40 | hosts: 41 | - ifconfig.co 42 | tls: 43 | - match: 44 | - port: 443 45 | sni_hosts: 46 | - ifconfig.co 47 | route: 48 | - destination: 49 | host: ifconfig.co 50 | port: 51 | number: 443 52 | weight: 100 53 | -------------------------------------------------------------------------------- /istio/helloworld-gw.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.istio.io/v1alpha3 2 | kind: Gateway 3 | metadata: 4 | name: helloworld-gateway 5 | spec: 6 | selector: 7 | istio: ingressgateway # use istio default controller 8 | servers: 9 | - port: 10 | number: 80 11 | name: http 12 | protocol: HTTP 13 | hosts: 14 | - "*" 15 | --- 16 | apiVersion: networking.istio.io/v1alpha3 17 | kind: VirtualService 18 | metadata: 19 | name: helloworld 20 | spec: 21 | hosts: 22 | - "*" 23 | gateways: 24 | - helloworld-gateway 25 | http: 26 | - match: 27 | - uri: 28 | prefix: /hello 29 | route: 30 | - destination: 31 | host: hello.default.svc.cluster.local 32 | port: 33 | number: 8080 34 | -------------------------------------------------------------------------------- /istio/helloworld-jwt-enable.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "authentication.istio.io/v1alpha1" 2 | kind: "Policy" 3 | metadata: 4 | name: "jwt-example" 5 | spec: 6 | targets: 7 | - name: hello 8 | peers: 9 | - mtls: {} 10 | origins: 11 | - jwt: 12 | issuer: "http-echo@http-echo.kubernetes.newtech.academy" 13 | jwksUri: "http://auth.kubernetes.newtech.academy/.well-known/jwks.json" 14 | principalBinding: USE_ORIGIN 15 | --- 16 | -------------------------------------------------------------------------------- /istio/helloworld-jwt.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.istio.io/v1alpha3 2 | kind: Gateway 3 | metadata: 4 | name: helloworld-gateway 5 | spec: 6 | selector: 7 | istio: ingressgateway # use istio default controller 8 | servers: 9 | - port: 10 | number: 80 11 | name: http 12 | protocol: HTTP 13 | hosts: 14 | - "*" 15 | --- 16 | apiVersion: networking.istio.io/v1alpha3 17 | kind: VirtualService 18 | metadata: 19 | name: helloworld-auth 20 | spec: 21 | hosts: 22 | - "auth.kubernetes.newtech.academy" 23 | gateways: 24 | - helloworld-gateway 25 | http: 26 | - route: 27 | - destination: 28 | host: auth.default.svc.cluster.local 29 | port: 30 | number: 8080 31 | --- 32 | apiVersion: networking.istio.io/v1alpha3 33 | kind: VirtualService 34 | metadata: 35 | name: helloworld-hello 36 | spec: 37 | hosts: 38 | - "hello.kubernetes.newtech.academy" 39 | gateways: 40 | - helloworld-gateway 41 | http: 42 | - route: 43 | - destination: 44 | host: hello.default.svc.cluster.local 45 | port: 46 | number: 8080 47 | --- 48 | apiVersion: apps/v1 49 | kind: Deployment 50 | metadata: 51 | name: auth 52 | spec: 53 | replicas: 1 54 | selector: 55 | matchLabels: 56 | app: auth 57 | template: 58 | metadata: 59 | labels: 60 | app: auth 61 | version: v1 62 | spec: 63 | containers: 64 | - name: auth 65 | image: wardviaene/http-echo 66 | env: 67 | - name: TEXT 68 | value: this is the authentication service 69 | ports: 70 | - name: http 71 | containerPort: 8080 72 | --- 73 | apiVersion: v1 74 | kind: Service 75 | metadata: 76 | name: auth 77 | labels: 78 | app: auth 79 | spec: 80 | selector: 81 | app: auth 82 | ports: 83 | - name: http 84 | port: 8080 85 | targetPort: 8080 86 | --- 87 | apiVersion: apps/v1 88 | kind: Deployment 89 | metadata: 90 | name: hello 91 | spec: 92 | replicas: 1 93 | selector: 94 | matchLabels: 95 | app: hello 96 | template: 97 | metadata: 98 | labels: 99 | app: hello 100 | version: v1 101 | spec: 102 | containers: 103 | - name: hello 104 | image: wardviaene/http-echo 105 | env: 106 | - name: TEXT 107 | value: Hello, you can only reach this service when authenticated 108 | ports: 109 | - name: http 110 | containerPort: 8080 111 | --- 112 | apiVersion: v1 113 | kind: Service 114 | metadata: 115 | name: hello 116 | labels: 117 | app: hello 118 | spec: 119 | selector: 120 | app: hello 121 | ports: 122 | - name: http 123 | port: 8080 124 | targetPort: 8080 125 | ### 126 | ### Enable TLS 127 | ### 128 | --- 129 | apiVersion: authentication.istio.io/v1alpha1 130 | kind: "MeshPolicy" 131 | metadata: 132 | name: "default" 133 | spec: 134 | peers: 135 | - mtls: {} 136 | --- 137 | apiVersion: networking.istio.io/v1alpha3 138 | kind: DestinationRule 139 | metadata: 140 | name: "enable-mtls" 141 | namespace: "default" # even though we specify a namespace, this rule applies to all namespaces 142 | spec: 143 | host: "*.local" 144 | trafficPolicy: 145 | tls: 146 | mode: ISTIO_MUTUAL 147 | --- 148 | apiVersion: networking.istio.io/v1alpha3 149 | kind: DestinationRule 150 | metadata: 151 | name: "api-server" 152 | spec: 153 | host: "kubernetes.default.svc.cluster.local" 154 | trafficPolicy: 155 | tls: 156 | mode: DISABLE 157 | -------------------------------------------------------------------------------- /istio/helloworld-rbac-enable.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "rbac.istio.io/v1alpha1" 2 | kind: RbacConfig 3 | metadata: 4 | name: default 5 | spec: 6 | mode: 'ON_WITH_INCLUSION' 7 | inclusion: 8 | namespaces: ["default"] 9 | --- 10 | apiVersion: authentication.istio.io/v1alpha1 11 | kind: "MeshPolicy" 12 | metadata: 13 | name: "default" 14 | spec: 15 | peers: 16 | - mtls: {} 17 | --- 18 | apiVersion: networking.istio.io/v1alpha3 19 | kind: DestinationRule 20 | metadata: 21 | name: "enable-mtls" 22 | namespace: "default" # even though we specify a namespace, this rule applies to all namespaces 23 | spec: 24 | host: "*.local" 25 | trafficPolicy: 26 | tls: 27 | mode: ISTIO_MUTUAL 28 | --- 29 | apiVersion: networking.istio.io/v1alpha3 30 | kind: DestinationRule 31 | metadata: 32 | name: "api-server" 33 | spec: 34 | host: "kubernetes.default.svc.cluster.local" 35 | trafficPolicy: 36 | tls: 37 | mode: DISABLE 38 | -------------------------------------------------------------------------------- /istio/helloworld-rbac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: "rbac.istio.io/v1alpha1" 2 | kind: ServiceRole 3 | metadata: 4 | name: hello-viewer 5 | namespace: default 6 | spec: 7 | rules: 8 | - services: ["hello.default.svc.cluster.local"] 9 | methods: ["GET", "HEAD"] 10 | --- 11 | apiVersion: "rbac.istio.io/v1alpha1" 12 | kind: ServiceRole 13 | metadata: 14 | name: world-viewer 15 | namespace: default 16 | spec: 17 | rules: 18 | - services: ["world.default.svc.cluster.local"] 19 | methods: ["GET", "HEAD"] 20 | --- 21 | apiVersion: "rbac.istio.io/v1alpha1" 22 | kind: ServiceRole 23 | metadata: 24 | name: world-2-viewer 25 | namespace: default 26 | spec: 27 | rules: 28 | - services: ["world-2.default.svc.cluster.local"] 29 | methods: ["GET", "HEAD"] 30 | --- 31 | apiVersion: "rbac.istio.io/v1alpha1" 32 | kind: ServiceRoleBinding 33 | metadata: 34 | name: istio-ingress-binding 35 | namespace: default 36 | spec: 37 | subjects: 38 | - properties: 39 | source.namespace: "istio-system" 40 | roleRef: 41 | kind: ServiceRole 42 | name: "hello-viewer" 43 | --- 44 | apiVersion: "rbac.istio.io/v1alpha1" 45 | kind: ServiceRoleBinding 46 | metadata: 47 | name: hello-user-binding 48 | namespace: default 49 | spec: 50 | subjects: 51 | - user: "cluster.local/ns/default/sa/hello" 52 | roleRef: 53 | kind: ServiceRole 54 | name: "world-viewer" 55 | --- 56 | apiVersion: "rbac.istio.io/v1alpha1" 57 | kind: ServiceRoleBinding 58 | metadata: 59 | name: world-user-binding 60 | namespace: default 61 | spec: 62 | subjects: 63 | - user: "cluster.local/ns/default/sa/world" 64 | roleRef: 65 | kind: ServiceRole 66 | name: "world-2-viewer" 67 | --- 68 | ### 69 | ### Kubernetes Service accounts 70 | ### 71 | apiVersion: v1 72 | kind: ServiceAccount 73 | metadata: 74 | name: hello 75 | --- 76 | apiVersion: v1 77 | kind: ServiceAccount 78 | metadata: 79 | name: world 80 | --- 81 | ### 82 | ### helloworld.yaml deployments, including a serviceaccount 83 | ### for the hello deployment and the world deployment 84 | ### 85 | apiVersion: apps/v1 86 | kind: Deployment 87 | metadata: 88 | name: hello 89 | spec: 90 | replicas: 1 91 | selector: 92 | matchLabels: 93 | app: hello 94 | template: 95 | metadata: 96 | labels: 97 | app: hello 98 | version: v1 99 | spec: 100 | serviceAccountName: hello # service account 101 | containers: 102 | - name: hello 103 | image: wardviaene/http-echo 104 | env: 105 | - name: TEXT 106 | value: hello 107 | - name: NEXT 108 | value: "world:8080" 109 | ports: 110 | - name: http 111 | containerPort: 8080 112 | --- 113 | apiVersion: v1 114 | kind: Service 115 | metadata: 116 | name: hello 117 | labels: 118 | app: hello 119 | spec: 120 | selector: 121 | app: hello 122 | ports: 123 | - name: http 124 | port: 8080 125 | targetPort: 8080 126 | --- 127 | apiVersion: apps/v1 128 | kind: Deployment 129 | metadata: 130 | name: world 131 | spec: 132 | replicas: 1 133 | selector: 134 | matchLabels: 135 | app: world 136 | template: 137 | metadata: 138 | labels: 139 | app: world 140 | version: v1 141 | spec: 142 | serviceAccountName: world # service account 143 | containers: 144 | - name: world 145 | image: wardviaene/http-echo 146 | env: 147 | - name: TEXT 148 | value: world 149 | - name: NEXT 150 | value: "world-2:8080" 151 | ports: 152 | - name: http 153 | containerPort: 8080 154 | --- 155 | apiVersion: v1 156 | kind: Service 157 | metadata: 158 | name: world 159 | labels: 160 | app: world 161 | spec: 162 | selector: 163 | app: world 164 | ports: 165 | - name: http 166 | port: 8080 167 | targetPort: 8080 168 | --- 169 | apiVersion: apps/v1 170 | kind: Deployment 171 | metadata: 172 | name: world-2 173 | spec: 174 | replicas: 1 175 | selector: 176 | matchLabels: 177 | app: world-2 178 | template: 179 | metadata: 180 | labels: 181 | app: world-2 182 | version: v1 183 | spec: 184 | containers: 185 | - name: world-2 186 | image: wardviaene/http-echo 187 | env: 188 | - name: TEXT 189 | value: "!!!" 190 | ports: 191 | - name: http 192 | containerPort: 8080 193 | --- 194 | apiVersion: v1 195 | kind: Service 196 | metadata: 197 | name: world-2 198 | labels: 199 | app: world-2 200 | spec: 201 | selector: 202 | app: world-2 203 | ports: 204 | - name: http 205 | port: 8080 206 | targetPort: 8080 207 | --- 208 | apiVersion: networking.istio.io/v1alpha3 209 | kind: Gateway 210 | metadata: 211 | name: helloworld-gateway 212 | spec: 213 | selector: 214 | istio: ingressgateway # use istio default controller 215 | servers: 216 | - port: 217 | number: 80 218 | name: http 219 | protocol: HTTP 220 | hosts: 221 | - "*" 222 | --- 223 | apiVersion: networking.istio.io/v1alpha3 224 | kind: VirtualService 225 | metadata: 226 | name: helloworld 227 | spec: 228 | hosts: 229 | - "hello-rbac.example.com" 230 | gateways: 231 | - helloworld-gateway 232 | http: 233 | - route: 234 | - destination: 235 | host: hello.default.svc.cluster.local 236 | subset: v1 237 | port: 238 | number: 8080 239 | --- 240 | apiVersion: networking.istio.io/v1alpha3 241 | kind: DestinationRule 242 | metadata: 243 | name: hello 244 | spec: 245 | host: hello.default.svc.cluster.local 246 | # uncomment to enable mutual TLS 247 | trafficPolicy: 248 | tls: 249 | mode: ISTIO_MUTUAL 250 | subsets: 251 | - name: v1 252 | labels: 253 | version: v1 254 | -------------------------------------------------------------------------------- /istio/helloworld-tls-enable.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: authentication.istio.io/v1alpha1 2 | kind: "MeshPolicy" 3 | metadata: 4 | name: "default" 5 | spec: 6 | peers: 7 | - mtls: {} 8 | --- 9 | apiVersion: networking.istio.io/v1alpha3 10 | kind: DestinationRule 11 | metadata: 12 | name: "enable-mtls" 13 | namespace: "default" # even though we specify a namespace, this rule applies to all namespaces 14 | spec: 15 | host: "*.local" 16 | trafficPolicy: 17 | tls: 18 | mode: ISTIO_MUTUAL 19 | --- 20 | apiVersion: networking.istio.io/v1alpha3 21 | kind: DestinationRule 22 | metadata: 23 | name: "api-server" 24 | spec: 25 | host: "kubernetes.default.svc.cluster.local" 26 | trafficPolicy: 27 | tls: 28 | mode: DISABLE 29 | --- 30 | apiVersion: networking.istio.io/v1alpha3 31 | kind: DestinationRule 32 | metadata: 33 | name: "legacy" 34 | spec: 35 | host: "end.legacy.svc.cluster.local" 36 | trafficPolicy: 37 | tls: 38 | mode: DISABLE 39 | -------------------------------------------------------------------------------- /istio/helloworld-tls-legacy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: legacy 5 | --- 6 | apiVersion: apps/v1 7 | kind: Deployment 8 | metadata: 9 | name: end-tls 10 | namespace: legacy 11 | spec: 12 | replicas: 1 13 | selector: 14 | matchLabels: 15 | app: end 16 | template: 17 | metadata: 18 | labels: 19 | app: end 20 | version: v1-tls 21 | spec: 22 | containers: 23 | - name: hello 24 | image: wardviaene/http-echo 25 | env: 26 | - name: TEXT 27 | value: "!!!" 28 | ports: 29 | - name: http 30 | containerPort: 8080 31 | --- 32 | apiVersion: apps/v1 33 | kind: Deployment 34 | metadata: 35 | name: hello-reverse-tls 36 | namespace: legacy 37 | spec: 38 | replicas: 1 39 | selector: 40 | matchLabels: 41 | app: hello-reverse 42 | template: 43 | metadata: 44 | labels: 45 | app: hello-reverse 46 | version: v1-tls 47 | spec: 48 | containers: 49 | - name: hello 50 | image: wardviaene/http-echo 51 | env: 52 | - name: TEXT 53 | value: hello 54 | - name: NEXT 55 | value: "world-reverse.ns2:8080" 56 | ports: 57 | - name: http 58 | containerPort: 8080 59 | --- 60 | apiVersion: v1 61 | kind: Service 62 | metadata: 63 | name: end 64 | namespace: legacy 65 | labels: 66 | app: end 67 | spec: 68 | selector: 69 | app: end 70 | ports: 71 | - name: http 72 | port: 8080 73 | targetPort: 8080 74 | --- 75 | apiVersion: v1 76 | kind: Service 77 | metadata: 78 | name: hello-reverse 79 | namespace: legacy 80 | labels: 81 | app: hello-reverse 82 | spec: 83 | selector: 84 | app: hello-reverse 85 | ports: 86 | - name: http 87 | port: 8080 88 | targetPort: 8080 89 | -------------------------------------------------------------------------------- /istio/helloworld-tls.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: ns1 5 | --- 6 | apiVersion: v1 7 | kind: Namespace 8 | metadata: 9 | name: ns2 10 | --- 11 | apiVersion: apps/v1 12 | kind: Deployment 13 | metadata: 14 | name: hello-tls 15 | namespace: ns1 16 | spec: 17 | replicas: 1 18 | selector: 19 | matchLabels: 20 | app: hello 21 | template: 22 | metadata: 23 | labels: 24 | app: hello 25 | version: v1-tls 26 | spec: 27 | containers: 28 | - name: hello 29 | image: wardviaene/http-echo 30 | env: 31 | - name: TEXT 32 | value: hello 33 | - name: NEXT 34 | value: "world.ns2:8080" 35 | ports: 36 | - name: http 37 | containerPort: 8080 38 | --- 39 | apiVersion: apps/v1 40 | kind: Deployment 41 | metadata: 42 | name: world-tls 43 | namespace: ns2 44 | spec: 45 | replicas: 1 46 | selector: 47 | matchLabels: 48 | app: world 49 | template: 50 | metadata: 51 | labels: 52 | app: world 53 | version: v1-tls 54 | spec: 55 | containers: 56 | - name: hello 57 | image: wardviaene/http-echo 58 | env: 59 | - name: TEXT 60 | value: world 61 | - name: NEXT 62 | value: "end.legacy:8080" 63 | ports: 64 | - name: http 65 | containerPort: 8080 66 | --- 67 | apiVersion: apps/v1 68 | kind: Deployment 69 | metadata: 70 | name: world-reverse-tls 71 | namespace: ns2 72 | spec: 73 | replicas: 1 74 | selector: 75 | matchLabels: 76 | app: world-reverse 77 | template: 78 | metadata: 79 | labels: 80 | app: world-reverse 81 | version: v1-tls 82 | spec: 83 | containers: 84 | - name: hello 85 | image: wardviaene/http-echo 86 | env: 87 | - name: TEXT 88 | value: world 89 | - name: NEXT 90 | value: "end-reverse.ns1:8080" 91 | ports: 92 | - name: http 93 | containerPort: 8080 94 | --- 95 | apiVersion: apps/v1 96 | kind: Deployment 97 | metadata: 98 | name: end-reverse-tls 99 | namespace: ns1 100 | spec: 101 | replicas: 1 102 | selector: 103 | matchLabels: 104 | app: end-reverse 105 | template: 106 | metadata: 107 | labels: 108 | app: end-reverse 109 | version: v1-tls 110 | spec: 111 | containers: 112 | - name: hello 113 | image: wardviaene/http-echo 114 | env: 115 | - name: TEXT 116 | value: "!!!" 117 | ports: 118 | - name: http 119 | containerPort: 8080 120 | --- 121 | apiVersion: v1 122 | kind: Service 123 | metadata: 124 | name: hello 125 | namespace: ns1 126 | labels: 127 | app: hello 128 | spec: 129 | selector: 130 | app: hello 131 | ports: 132 | - name: http 133 | port: 8080 134 | targetPort: 8080 135 | --- 136 | apiVersion: v1 137 | kind: Service 138 | metadata: 139 | name: world 140 | namespace: ns2 141 | labels: 142 | app: world 143 | spec: 144 | selector: 145 | app: world 146 | ports: 147 | - name: http 148 | port: 8080 149 | targetPort: 8080 150 | --- 151 | apiVersion: v1 152 | kind: Service 153 | metadata: 154 | name: world-reverse 155 | namespace: ns2 156 | labels: 157 | app: world-reverse 158 | spec: 159 | selector: 160 | app: world-reverse 161 | ports: 162 | - name: http 163 | port: 8080 164 | targetPort: 8080 165 | --- 166 | apiVersion: v1 167 | kind: Service 168 | metadata: 169 | name: end-reverse 170 | namespace: ns1 171 | labels: 172 | app: end-reverse 173 | spec: 174 | selector: 175 | app: end-reverse 176 | ports: 177 | - name: http 178 | port: 8080 179 | targetPort: 8080 180 | --- 181 | apiVersion: networking.istio.io/v1alpha3 182 | kind: Gateway 183 | metadata: 184 | name: helloworld-gateway 185 | spec: 186 | selector: 187 | istio: ingressgateway # use istio default controller 188 | servers: 189 | - port: 190 | number: 80 191 | name: http 192 | protocol: HTTP 193 | hosts: 194 | - "*" 195 | --- 196 | apiVersion: networking.istio.io/v1alpha3 197 | kind: DestinationRule 198 | metadata: 199 | name: hello 200 | spec: 201 | host: hello.ns1.svc.cluster.local 202 | # uncomment to enable mutual TLS 203 | trafficPolicy: 204 | tls: 205 | mode: ISTIO_MUTUAL 206 | subsets: 207 | - name: v1-tls 208 | labels: 209 | version: v1-tls 210 | --- 211 | apiVersion: networking.istio.io/v1alpha3 212 | kind: DestinationRule 213 | metadata: 214 | name: hello-reverse 215 | spec: 216 | host: hello-reverse.legacy.svc.cluster.local 217 | # uncomment to enable mutual TLS 218 | trafficPolicy: 219 | tls: 220 | mode: ISTIO_MUTUAL 221 | subsets: 222 | - name: v1-tls 223 | labels: 224 | version: v1-tls 225 | --- 226 | apiVersion: networking.istio.io/v1alpha3 227 | kind: VirtualService 228 | metadata: 229 | name: helloworld-tls 230 | spec: 231 | hosts: 232 | - "hello-tls.example.com" 233 | gateways: 234 | - helloworld-gateway 235 | http: 236 | - route: 237 | - destination: 238 | host: hello.ns1.svc.cluster.local 239 | subset: v1-tls # match v3 only 240 | port: 241 | number: 8080 242 | --- 243 | apiVersion: networking.istio.io/v1alpha3 244 | kind: VirtualService 245 | metadata: 246 | name: helloworld-tls-reverse 247 | spec: 248 | hosts: 249 | - "hello-tls-reverse.example.com" 250 | gateways: 251 | - helloworld-gateway 252 | http: 253 | - route: 254 | - destination: 255 | host: hello-reverse.legacy.svc.cluster.local 256 | subset: v1-tls 257 | port: 258 | number: 8080 259 | -------------------------------------------------------------------------------- /istio/helloworld-v2-canary.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.istio.io/v1alpha3 2 | kind: DestinationRule 3 | metadata: 4 | name: hello 5 | spec: 6 | host: hello.default.svc.cluster.local 7 | subsets: 8 | - name: v1 9 | labels: 10 | version: v1 11 | - name: v2 12 | labels: 13 | version: v2 14 | --- 15 | apiVersion: networking.istio.io/v1alpha3 16 | kind: VirtualService 17 | metadata: 18 | name: helloworld 19 | spec: 20 | hosts: 21 | - "hello.example.com" 22 | gateways: 23 | - helloworld-gateway 24 | http: 25 | - route: 26 | - destination: 27 | host: hello.default.svc.cluster.local 28 | subset: v1 29 | port: 30 | number: 8080 31 | weight: 90 32 | - destination: 33 | host: hello.default.svc.cluster.local 34 | subset: v2 35 | port: 36 | number: 8080 37 | weight: 10 38 | -------------------------------------------------------------------------------- /istio/helloworld-v2-routing.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.istio.io/v1alpha3 2 | kind: DestinationRule 3 | metadata: 4 | name: hello 5 | spec: 6 | host: hello.default.svc.cluster.local 7 | subsets: 8 | - name: v1 9 | labels: 10 | version: v1 11 | - name: v2 12 | labels: 13 | version: v2 14 | --- 15 | apiVersion: networking.istio.io/v1alpha3 16 | kind: VirtualService 17 | metadata: 18 | name: helloworld 19 | spec: 20 | hosts: 21 | - "hello.example.com" 22 | gateways: 23 | - helloworld-gateway 24 | http: 25 | - match: 26 | - headers: 27 | end-user: 28 | exact: john 29 | route: 30 | - destination: 31 | host: hello.default.svc.cluster.local 32 | subset: v2 # match v2 only 33 | port: 34 | number: 8080 35 | - route: # default route for hello.example.com 36 | - destination: 37 | host: hello.default.svc.cluster.local 38 | subset: v1 # match v1 only 39 | port: 40 | number: 8080 41 | -------------------------------------------------------------------------------- /istio/helloworld-v2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: hello-v2 5 | spec: 6 | replicas: 3 7 | selector: 8 | matchLabels: 9 | app: hello 10 | template: 11 | metadata: 12 | labels: 13 | app: hello 14 | version: v2 15 | spec: 16 | containers: 17 | - name: hello 18 | image: wardviaene/http-echo 19 | env: 20 | - name: TEXT 21 | value: hello, this is v2 22 | - name: NEXT 23 | value: "world-2:8080" 24 | ports: 25 | - name: http 26 | containerPort: 8080 27 | -------------------------------------------------------------------------------- /istio/helloworld-v3.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: hello-v3 5 | spec: 6 | replicas: 2 7 | selector: 8 | matchLabels: 9 | app: hello 10 | template: 11 | metadata: 12 | labels: 13 | app: hello 14 | version: v3 15 | spec: 16 | containers: 17 | - name: hello 18 | image: wardviaene/http-echo 19 | env: 20 | - name: MY_POD_NAME 21 | valueFrom: 22 | fieldRef: 23 | fieldPath: metadata.name 24 | - name: TEXT 25 | value: hello, this is $(MY_POD_NAME) 26 | ports: 27 | - name: http 28 | containerPort: 8080 29 | --- 30 | apiVersion: apps/v1 31 | kind: Deployment 32 | metadata: 33 | name: hello-v3-latency 34 | spec: 35 | replicas: 1 36 | selector: 37 | matchLabels: 38 | app: hello 39 | template: 40 | metadata: 41 | labels: 42 | app: hello 43 | version: v3 44 | spec: 45 | containers: 46 | - name: hello 47 | image: wardviaene/http-echo 48 | env: 49 | - name: MY_POD_NAME 50 | valueFrom: 51 | fieldRef: 52 | fieldPath: metadata.name 53 | - name: TEXT 54 | value: hello, this is $(MY_POD_NAME) 55 | - name: LATENCY 56 | value: "5" 57 | ports: 58 | - name: http 59 | containerPort: 8080 60 | --- 61 | apiVersion: networking.istio.io/v1alpha3 62 | kind: DestinationRule 63 | metadata: 64 | name: hello 65 | spec: 66 | host: hello.default.svc.cluster.local 67 | subsets: 68 | - name: v1 69 | labels: 70 | version: v1 71 | - name: v2 72 | labels: 73 | version: v2 74 | - name: v3 75 | labels: 76 | version: v3 77 | --- 78 | apiVersion: networking.istio.io/v1alpha3 79 | kind: VirtualService 80 | metadata: 81 | name: helloworld-v3 82 | spec: 83 | hosts: 84 | - "hello-v3.example.com" 85 | gateways: 86 | - helloworld-gateway 87 | http: 88 | - route: # default route for hello.example.com 89 | - destination: 90 | host: hello.default.svc.cluster.local 91 | subset: v3 # match v3 only 92 | port: 93 | number: 8080 94 | timeout: 10s 95 | retries: 96 | attempts: 2 97 | perTryTimeout: 2s 98 | -------------------------------------------------------------------------------- /istio/helloworld.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: hello 5 | spec: 6 | replicas: 3 7 | selector: 8 | matchLabels: 9 | app: hello 10 | template: 11 | metadata: 12 | labels: 13 | app: hello 14 | version: v1 15 | spec: 16 | containers: 17 | - name: hello 18 | image: wardviaene/http-echo 19 | env: 20 | - name: TEXT 21 | value: hello 22 | - name: NEXT 23 | value: "world:8080" 24 | ports: 25 | - name: http 26 | containerPort: 8080 27 | --- 28 | apiVersion: v1 29 | kind: Service 30 | metadata: 31 | name: hello 32 | labels: 33 | app: hello 34 | spec: 35 | selector: 36 | app: hello 37 | ports: 38 | - name: http 39 | port: 8080 40 | targetPort: 8080 41 | --- 42 | apiVersion: apps/v1 43 | kind: Deployment 44 | metadata: 45 | name: world 46 | spec: 47 | replicas: 3 48 | selector: 49 | matchLabels: 50 | app: world 51 | template: 52 | metadata: 53 | labels: 54 | app: world 55 | version: v1 56 | spec: 57 | containers: 58 | - name: world 59 | image: wardviaene/http-echo 60 | env: 61 | - name: TEXT 62 | value: world 63 | - name: NEXT 64 | value: "world-2:8080" 65 | ports: 66 | - name: http 67 | containerPort: 8080 68 | --- 69 | apiVersion: v1 70 | kind: Service 71 | metadata: 72 | name: world 73 | labels: 74 | app: world 75 | spec: 76 | selector: 77 | app: world 78 | ports: 79 | - name: http 80 | port: 8080 81 | targetPort: 8080 82 | --- 83 | apiVersion: apps/v1 84 | kind: Deployment 85 | metadata: 86 | name: world-2 87 | spec: 88 | replicas: 3 89 | selector: 90 | matchLabels: 91 | app: world-2 92 | template: 93 | metadata: 94 | labels: 95 | app: world-2 96 | version: v1 97 | spec: 98 | containers: 99 | - name: world-2 100 | image: wardviaene/http-echo 101 | env: 102 | - name: TEXT 103 | value: "!!!" 104 | ports: 105 | - name: http 106 | containerPort: 8080 107 | --- 108 | apiVersion: v1 109 | kind: Service 110 | metadata: 111 | name: world-2 112 | labels: 113 | app: world-2 114 | spec: 115 | selector: 116 | app: world-2 117 | ports: 118 | - name: http 119 | port: 8080 120 | targetPort: 8080 121 | --- 122 | -------------------------------------------------------------------------------- /kubeless/README.md: -------------------------------------------------------------------------------- 1 | # Install CLI 2 | ``` 3 | wget https://github.com/kubeless/kubeless/releases/download/v1.0.2/kubeless_linux-amd64.zip 4 | unzip kubeless_linux-amd64.zip 5 | sudo mv bundles/kubeless_linux-amd64/kubeless /usr/local/bin 6 | rm -r bundles/ 7 | ``` 8 | 9 | # Deploy kubeless 10 | ``` 11 | kubectl create ns kubeless 12 | kubectl create -f https://github.com/kubeless/kubeless/releases/download/v1.0.2/kubeless-v1.0.2.yaml 13 | ``` 14 | 15 | # Example function 16 | 17 | ## python 18 | ``` 19 | kubeless function deploy hello --runtime python2.7 \ 20 | --from-file python-example/example.py \ 21 | --handler test.hello 22 | ``` 23 | ## NodeJS 24 | ``` 25 | kubeless function deploy myfunction --runtime nodejs6 \ 26 | --dependencies node-example/package.json \ 27 | --handler test.myfunction \ 28 | --from-file node-example/example.js 29 | ``` 30 | 31 | # Commands 32 | 33 | ## List Function 34 | ``` 35 | kubeless function ls 36 | ``` 37 | ## Call Function 38 | ``` 39 | kubeless function call myfunction --data 'This is some data' 40 | ``` 41 | 42 | ## Expose function 43 | ``` 44 | kubectl create -f nginx-ingress-controller-with-elb.yml 45 | kubeless trigger http create myfunction --function-name myfunction --hostname myfunction.kubernetes.newtech.academy 46 | ``` 47 | 48 | 49 | # PubSub 50 | ## Kafka Installation 51 | ``` 52 | export RELEASE=$(curl -s https://api.github.com/repos/kubeless/kafka-trigger/releases/latest | grep tag_name | cut -d '"' -f 4) 53 | kubectl create -f https://github.com/kubeless/kafka-trigger/releases/download/$RELEASE/kafka-zookeeper-$RELEASE.yaml 54 | ``` 55 | 56 | ## Deploy function 57 | ``` 58 | kubeless function deploy uppercase --runtime nodejs6 \ 59 | --dependencies node-example/package.json \ 60 | --handler test.uppercase \ 61 | --from-file node-example/uppercase.js 62 | ``` 63 | 64 | ## Trigger and publish 65 | ``` 66 | kubeless trigger kafka create test --function-selector created-by=kubeless,function=uppercase --trigger-topic uppercase 67 | kubeless topic publish --topic uppercase --data "this message will be converted to uppercase" 68 | ``` 69 | -------------------------------------------------------------------------------- /kubeless/nginx-ingress-controller-with-elb.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | apiVersion: v1 4 | kind: Namespace 5 | metadata: 6 | name: ingress-nginx 7 | --- 8 | 9 | apiVersion: apps/v1 10 | kind: Deployment 11 | metadata: 12 | name: default-http-backend 13 | labels: 14 | app.kubernetes.io/name: default-http-backend 15 | app.kubernetes.io/part-of: ingress-nginx 16 | namespace: ingress-nginx 17 | spec: 18 | replicas: 1 19 | selector: 20 | matchLabels: 21 | app.kubernetes.io/name: default-http-backend 22 | template: 23 | metadata: 24 | labels: 25 | app.kubernetes.io/name: default-http-backend 26 | app.kubernetes.io/part-of: ingress-nginx 27 | spec: 28 | terminationGracePeriodSeconds: 60 29 | containers: 30 | - name: default-http-backend 31 | # Any image is permissible as long as: 32 | # 1. It serves a 404 page at / 33 | # 2. It serves 200 on a /healthz endpoint 34 | image: gcr.io/google_containers/defaultbackend:1.4 35 | livenessProbe: 36 | httpGet: 37 | path: /healthz 38 | port: 8080 39 | scheme: HTTP 40 | initialDelaySeconds: 30 41 | timeoutSeconds: 5 42 | ports: 43 | - containerPort: 8080 44 | resources: 45 | limits: 46 | cpu: 10m 47 | memory: 20Mi 48 | requests: 49 | cpu: 10m 50 | memory: 20Mi 51 | --- 52 | 53 | apiVersion: v1 54 | kind: Service 55 | metadata: 56 | name: default-http-backend 57 | namespace: ingress-nginx 58 | labels: 59 | app.kubernetes.io/name: default-http-backend 60 | app.kubernetes.io/part-of: ingress-nginx 61 | spec: 62 | ports: 63 | - port: 80 64 | targetPort: 8080 65 | selector: 66 | app.kubernetes.io/name: default-http-backend 67 | --- 68 | 69 | kind: ConfigMap 70 | apiVersion: v1 71 | metadata: 72 | name: nginx-configuration 73 | namespace: ingress-nginx 74 | labels: 75 | app.kubernetes.io/name: ingress-nginx 76 | app.kubernetes.io/part-of: ingress-nginx 77 | data: 78 | use-proxy-protocol: "true" 79 | --- 80 | 81 | kind: ConfigMap 82 | apiVersion: v1 83 | metadata: 84 | name: tcp-services 85 | namespace: ingress-nginx 86 | labels: 87 | app.kubernetes.io/name: ingress-nginx 88 | app.kubernetes.io/part-of: ingress-nginx 89 | --- 90 | 91 | kind: ConfigMap 92 | apiVersion: v1 93 | metadata: 94 | name: udp-services 95 | namespace: ingress-nginx 96 | labels: 97 | app.kubernetes.io/name: ingress-nginx 98 | app.kubernetes.io/part-of: ingress-nginx 99 | --- 100 | 101 | apiVersion: v1 102 | kind: ServiceAccount 103 | metadata: 104 | name: nginx-ingress-serviceaccount 105 | namespace: ingress-nginx 106 | labels: 107 | app.kubernetes.io/name: ingress-nginx 108 | app.kubernetes.io/part-of: ingress-nginx 109 | 110 | --- 111 | 112 | apiVersion: rbac.authorization.k8s.io/v1beta1 113 | kind: ClusterRole 114 | metadata: 115 | name: nginx-ingress-clusterrole 116 | labels: 117 | app.kubernetes.io/name: ingress-nginx 118 | app.kubernetes.io/part-of: ingress-nginx 119 | rules: 120 | - apiGroups: 121 | - "" 122 | resources: 123 | - configmaps 124 | - endpoints 125 | - nodes 126 | - pods 127 | - secrets 128 | verbs: 129 | - list 130 | - watch 131 | - apiGroups: 132 | - "" 133 | resources: 134 | - nodes 135 | verbs: 136 | - get 137 | - apiGroups: 138 | - "" 139 | resources: 140 | - services 141 | verbs: 142 | - get 143 | - list 144 | - watch 145 | - apiGroups: 146 | - "extensions" 147 | resources: 148 | - ingresses 149 | verbs: 150 | - get 151 | - list 152 | - watch 153 | - apiGroups: 154 | - "" 155 | resources: 156 | - events 157 | verbs: 158 | - create 159 | - patch 160 | - apiGroups: 161 | - "extensions" 162 | resources: 163 | - ingresses/status 164 | verbs: 165 | - update 166 | 167 | --- 168 | 169 | apiVersion: rbac.authorization.k8s.io/v1beta1 170 | kind: Role 171 | metadata: 172 | name: nginx-ingress-role 173 | namespace: ingress-nginx 174 | labels: 175 | app.kubernetes.io/name: ingress-nginx 176 | app.kubernetes.io/part-of: ingress-nginx 177 | rules: 178 | - apiGroups: 179 | - "" 180 | resources: 181 | - configmaps 182 | - pods 183 | - secrets 184 | - namespaces 185 | verbs: 186 | - get 187 | - apiGroups: 188 | - "" 189 | resources: 190 | - configmaps 191 | resourceNames: 192 | # Defaults to "-" 193 | # Here: "-" 194 | # This has to be adapted if you change either parameter 195 | # when launching the nginx-ingress-controller. 196 | - "ingress-controller-leader-nginx" 197 | verbs: 198 | - get 199 | - update 200 | - apiGroups: 201 | - "" 202 | resources: 203 | - configmaps 204 | verbs: 205 | - create 206 | - apiGroups: 207 | - "" 208 | resources: 209 | - endpoints 210 | verbs: 211 | - get 212 | 213 | --- 214 | 215 | apiVersion: rbac.authorization.k8s.io/v1beta1 216 | kind: RoleBinding 217 | metadata: 218 | name: nginx-ingress-role-nisa-binding 219 | namespace: ingress-nginx 220 | labels: 221 | app.kubernetes.io/name: ingress-nginx 222 | app.kubernetes.io/part-of: ingress-nginx 223 | roleRef: 224 | apiGroup: rbac.authorization.k8s.io 225 | kind: Role 226 | name: nginx-ingress-role 227 | subjects: 228 | - kind: ServiceAccount 229 | name: nginx-ingress-serviceaccount 230 | namespace: ingress-nginx 231 | 232 | --- 233 | 234 | apiVersion: rbac.authorization.k8s.io/v1beta1 235 | kind: ClusterRoleBinding 236 | metadata: 237 | name: nginx-ingress-clusterrole-nisa-binding 238 | labels: 239 | app.kubernetes.io/name: ingress-nginx 240 | app.kubernetes.io/part-of: ingress-nginx 241 | roleRef: 242 | apiGroup: rbac.authorization.k8s.io 243 | kind: ClusterRole 244 | name: nginx-ingress-clusterrole 245 | subjects: 246 | - kind: ServiceAccount 247 | name: nginx-ingress-serviceaccount 248 | namespace: ingress-nginx 249 | --- 250 | 251 | apiVersion: apps/v1 252 | kind: Deployment 253 | metadata: 254 | name: nginx-ingress-controller 255 | namespace: ingress-nginx 256 | labels: 257 | app.kubernetes.io/name: ingress-nginx 258 | app.kubernetes.io/part-of: ingress-nginx 259 | spec: 260 | replicas: 1 261 | selector: 262 | matchLabels: 263 | app.kubernetes.io/name: ingress-nginx 264 | template: 265 | metadata: 266 | labels: 267 | app.kubernetes.io/name: ingress-nginx 268 | annotations: 269 | prometheus.io/port: '10254' 270 | prometheus.io/scrape: 'true' 271 | spec: 272 | serviceAccountName: nginx-ingress-serviceaccount 273 | containers: 274 | - name: nginx-ingress-controller 275 | image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.18.0 276 | args: 277 | - /nginx-ingress-controller 278 | - --default-backend-service=$(POD_NAMESPACE)/default-http-backend 279 | - --configmap=$(POD_NAMESPACE)/nginx-configuration 280 | - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services 281 | - --udp-services-configmap=$(POD_NAMESPACE)/udp-services 282 | - --publish-service=$(POD_NAMESPACE)/ingress-nginx 283 | - --annotations-prefix=nginx.ingress.kubernetes.io 284 | securityContext: 285 | capabilities: 286 | drop: 287 | - ALL 288 | add: 289 | - NET_BIND_SERVICE 290 | # www-data -> 33 291 | runAsUser: 33 292 | env: 293 | - name: POD_NAME 294 | valueFrom: 295 | fieldRef: 296 | fieldPath: metadata.name 297 | - name: POD_NAMESPACE 298 | valueFrom: 299 | fieldRef: 300 | fieldPath: metadata.namespace 301 | ports: 302 | - name: http 303 | containerPort: 80 304 | - name: https 305 | containerPort: 443 306 | livenessProbe: 307 | failureThreshold: 3 308 | httpGet: 309 | path: /healthz 310 | port: 10254 311 | scheme: HTTP 312 | initialDelaySeconds: 10 313 | periodSeconds: 10 314 | successThreshold: 1 315 | timeoutSeconds: 1 316 | readinessProbe: 317 | failureThreshold: 3 318 | httpGet: 319 | path: /healthz 320 | port: 10254 321 | scheme: HTTP 322 | periodSeconds: 10 323 | successThreshold: 1 324 | timeoutSeconds: 1 325 | --- 326 | kind: Service 327 | apiVersion: v1 328 | metadata: 329 | name: ingress-nginx 330 | namespace: ingress-nginx 331 | labels: 332 | app.kubernetes.io/name: ingress-nginx 333 | app.kubernetes.io/part-of: ingress-nginx 334 | annotations: 335 | # Enable PROXY protocol 336 | service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: '*' 337 | # Increase the ELB idle timeout to avoid issues with WebSockets or Server-Sent Events. 338 | service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: '3600' 339 | spec: 340 | type: LoadBalancer 341 | selector: 342 | app.kubernetes.io/name: ingress-nginx 343 | ports: 344 | - name: http 345 | port: 80 346 | targetPort: http 347 | - name: https 348 | port: 443 349 | targetPort: https 350 | -------------------------------------------------------------------------------- /kubeless/node-example/example.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | myfunction: function (event, context) { 3 | console.log(event); 4 | return "Hello world!"; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /kubeless/node-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-example", 3 | "version": "0.0.1", 4 | "scripts": { 5 | "start": "node example.js" 6 | }, 7 | "engines": { 8 | "node": "^6.14.4" 9 | }, 10 | "dependencies": { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /kubeless/node-example/uppercase.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | uppercase: function (event, context) { 3 | str = event['data'].toUpperCase() 4 | console.log(str); 5 | return str 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /kubeless/python-example/example.py: -------------------------------------------------------------------------------- 1 | def hello(event, context): 2 | print event 3 | return event['data'] 4 | -------------------------------------------------------------------------------- /metrics-server/auth-delegator.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1beta1 3 | kind: ClusterRoleBinding 4 | metadata: 5 | name: metrics-server:system:auth-delegator 6 | roleRef: 7 | apiGroup: rbac.authorization.k8s.io 8 | kind: ClusterRole 9 | name: system:auth-delegator 10 | subjects: 11 | - kind: ServiceAccount 12 | name: metrics-server 13 | namespace: kube-system 14 | -------------------------------------------------------------------------------- /metrics-server/auth-reader.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1beta1 3 | kind: RoleBinding 4 | metadata: 5 | name: metrics-server-auth-reader 6 | namespace: kube-system 7 | roleRef: 8 | apiGroup: rbac.authorization.k8s.io 9 | kind: Role 10 | name: extension-apiserver-authentication-reader 11 | subjects: 12 | - kind: ServiceAccount 13 | name: metrics-server 14 | namespace: kube-system 15 | -------------------------------------------------------------------------------- /metrics-server/metrics-apiservice.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apiregistration.k8s.io/v1beta1 3 | kind: APIService 4 | metadata: 5 | name: v1beta1.metrics.k8s.io 6 | spec: 7 | service: 8 | name: metrics-server 9 | namespace: kube-system 10 | group: metrics.k8s.io 11 | version: v1beta1 12 | insecureSkipTLSVerify: true 13 | groupPriorityMinimum: 100 14 | versionPriority: 100 15 | -------------------------------------------------------------------------------- /metrics-server/metrics-server-deployment.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: metrics-server 6 | namespace: kube-system 7 | --- 8 | apiVersion: apps/v1 9 | kind: Deployment 10 | metadata: 11 | name: metrics-server 12 | namespace: kube-system 13 | labels: 14 | k8s-app: metrics-server 15 | spec: 16 | selector: 17 | matchLabels: 18 | k8s-app: metrics-server 19 | template: 20 | metadata: 21 | name: metrics-server 22 | labels: 23 | k8s-app: metrics-server 24 | spec: 25 | serviceAccountName: metrics-server 26 | containers: 27 | - name: metrics-server 28 | image: gcr.io/google_containers/metrics-server-amd64:v0.2.1 29 | imagePullPolicy: Always 30 | command: 31 | - /metrics-server 32 | - --source=kubernetes.summary_api:'' 33 | -------------------------------------------------------------------------------- /metrics-server/metrics-server-service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: metrics-server 6 | namespace: kube-system 7 | labels: 8 | kubernetes.io/name: "Metrics-server" 9 | spec: 10 | selector: 11 | k8s-app: metrics-server 12 | ports: 13 | - port: 443 14 | protocol: TCP 15 | targetPort: 443 16 | -------------------------------------------------------------------------------- /metrics-server/resource-reader.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: system:metrics-server 6 | rules: 7 | - apiGroups: 8 | - "" 9 | resources: 10 | - pods 11 | - nodes 12 | - nodes/stats 13 | - namespaces 14 | verbs: 15 | - get 16 | - list 17 | - watch 18 | - apiGroups: 19 | - "extensions" 20 | resources: 21 | - deployments 22 | verbs: 23 | - get 24 | - list 25 | - watch 26 | --- 27 | apiVersion: rbac.authorization.k8s.io/v1 28 | kind: ClusterRoleBinding 29 | metadata: 30 | name: system:metrics-server 31 | roleRef: 32 | apiGroup: rbac.authorization.k8s.io 33 | kind: ClusterRole 34 | name: system:metrics-server 35 | subjects: 36 | - kind: ServiceAccount 37 | name: metrics-server 38 | namespace: kube-system 39 | -------------------------------------------------------------------------------- /mutatingwebhook/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Build go project 3 | # 4 | FROM golang:1.15-alpine as go-builder 5 | 6 | WORKDIR /go/src/github.com/wardviaene/kubernetes-course/mutatingwebhook 7 | 8 | COPY . . 9 | 10 | RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o mutatingwebhook *.go 11 | 12 | # 13 | # Runtime container 14 | # 15 | FROM alpine:latest 16 | 17 | RUN mkdir -p /app && \ 18 | addgroup -S app && adduser -S app -G app && \ 19 | chown app:app /app 20 | 21 | WORKDIR /app 22 | 23 | COPY --from=go-builder /go/src/github.com/wardviaene/kubernetes-course/mutatingwebhook . 24 | 25 | USER app 26 | 27 | CMD ["./mutatingwebhook"] 28 | -------------------------------------------------------------------------------- /mutatingwebhook/README.md: -------------------------------------------------------------------------------- 1 | # Mutating Webhook example 2 | 3 | ## Setup the webhook 4 | 5 | ``` 6 | kubectl apply -f webhook.yaml 7 | ``` 8 | 9 | ## Set up the CA Certificate 10 | Once the webhook runs (give it a few seconds to initialize), the CA certificate can be downloaded by executing a curl command within the container. To retrieve the base64 encoded version of this ca.pem, use the following command: 11 | ``` 12 | kubectl exec -it -n mutatingwebhook $(kubectl get pods --no-headers -o custom-columns=":metadata.name" -n mutatingwebhook) -- wget -q -O- localhost:8080/ca.pem?base64 13 | ``` 14 | 15 | The output of this command should replace the base64 string in caBundle in webhook.yaml: 16 | ``` 17 | caBundle: "cGxhY2Vob2xkZXIK" # <= replace this string within quotes 18 | ``` 19 | 20 | Then reapply the webhook using: 21 | ``` 22 | kubectl apply -f webhook.yaml 23 | ``` 24 | -------------------------------------------------------------------------------- /mutatingwebhook/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/wardviaene/kubernetes-course/mutatingwebhook 2 | 3 | go 1.15 4 | -------------------------------------------------------------------------------- /mutatingwebhook/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "crypto/rand" 6 | "crypto/rsa" 7 | "crypto/tls" 8 | "crypto/x509" 9 | "crypto/x509/pkix" 10 | "encoding/pem" 11 | "fmt" 12 | "log" 13 | "math/big" 14 | "net" 15 | "net/http" 16 | "time" 17 | ) 18 | 19 | func main() { 20 | 21 | // setup certs 22 | fmt.Printf("Initializing certificates...\n") 23 | serverTLSConf, clientTLSConf, caPEM, err := certsetup() 24 | if err != nil { 25 | panic(err) 26 | } 27 | 28 | s := Server{ 29 | ServerTLSConf: serverTLSConf, 30 | ClientTLSConf: clientTLSConf, 31 | CaPEM: caPEM, 32 | } 33 | 34 | go func() { 35 | handler := http.NewServeMux() 36 | 37 | handler.HandleFunc("/ca.pem", s.getCA) 38 | fmt.Printf("Starting localhost http server on :8080 with ca.pem endpoint\n") 39 | err = http.ListenAndServe("localhost:8080", handler) 40 | 41 | if err != nil { 42 | log.Fatal(err) 43 | } 44 | }() 45 | 46 | // start TLS server 47 | fmt.Printf("Starting TLS server on :8443\n") 48 | handler := http.NewServeMux() 49 | handler.HandleFunc("/webhook", s.postWebhook) 50 | 51 | https := &http.Server{ 52 | Addr: ":8443", 53 | TLSConfig: serverTLSConf, 54 | Handler: handler, 55 | } 56 | 57 | log.Fatal(https.ListenAndServeTLS("", "")) 58 | 59 | } 60 | 61 | // certsetup adapted from https://gist.github.com/shaneutt/5e1995295cff6721c89a71d13a71c251 62 | func certsetup() (serverTLSConf *tls.Config, clientTLSConf *tls.Config, caPEMBytes []byte, err error) { 63 | // set up our CA certificate 64 | ca := &x509.Certificate{ 65 | SerialNumber: big.NewInt(2019), 66 | Subject: pkix.Name{ 67 | Organization: []string{"Company, INC."}, 68 | Country: []string{"US"}, 69 | Province: []string{""}, 70 | Locality: []string{"San Francisco"}, 71 | StreetAddress: []string{"Golden Gate Bridge"}, 72 | PostalCode: []string{"94016"}, 73 | }, 74 | NotBefore: time.Now(), 75 | NotAfter: time.Now().AddDate(10, 0, 0), 76 | IsCA: true, 77 | ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, 78 | KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, 79 | BasicConstraintsValid: true, 80 | } 81 | 82 | // create our private and public key 83 | caPrivKey, err := rsa.GenerateKey(rand.Reader, 4096) 84 | if err != nil { 85 | return nil, nil, []byte{}, err 86 | } 87 | 88 | // create the CA 89 | caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caPrivKey.PublicKey, caPrivKey) 90 | if err != nil { 91 | return nil, nil, []byte{}, err 92 | } 93 | 94 | // pem encode 95 | caPEM := new(bytes.Buffer) 96 | pem.Encode(caPEM, &pem.Block{ 97 | Type: "CERTIFICATE", 98 | Bytes: caBytes, 99 | }) 100 | 101 | caPrivKeyPEM := new(bytes.Buffer) 102 | pem.Encode(caPrivKeyPEM, &pem.Block{ 103 | Type: "RSA PRIVATE KEY", 104 | Bytes: x509.MarshalPKCS1PrivateKey(caPrivKey), 105 | }) 106 | 107 | // set up our server certificate 108 | cert := &x509.Certificate{ 109 | SerialNumber: big.NewInt(2019), 110 | Subject: pkix.Name{ 111 | Organization: []string{"Company, INC."}, 112 | Country: []string{"US"}, 113 | Province: []string{""}, 114 | Locality: []string{"San Francisco"}, 115 | StreetAddress: []string{"Golden Gate Bridge"}, 116 | PostalCode: []string{"94016"}, 117 | }, 118 | IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1), net.IPv6loopback}, 119 | NotBefore: time.Now(), 120 | NotAfter: time.Now().AddDate(10, 0, 0), 121 | SubjectKeyId: []byte{1, 2, 3, 4, 6}, 122 | ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, 123 | KeyUsage: x509.KeyUsageDigitalSignature, 124 | DNSNames: []string{"mutatingwebhook.mutatingwebhook.svc"}, 125 | } 126 | 127 | certPrivKey, err := rsa.GenerateKey(rand.Reader, 4096) 128 | if err != nil { 129 | return nil, nil, []byte{}, err 130 | } 131 | 132 | certBytes, err := x509.CreateCertificate(rand.Reader, cert, ca, &certPrivKey.PublicKey, caPrivKey) 133 | if err != nil { 134 | return nil, nil, []byte{}, err 135 | } 136 | 137 | certPEM := new(bytes.Buffer) 138 | pem.Encode(certPEM, &pem.Block{ 139 | Type: "CERTIFICATE", 140 | Bytes: certBytes, 141 | }) 142 | 143 | certPrivKeyPEM := new(bytes.Buffer) 144 | pem.Encode(certPrivKeyPEM, &pem.Block{ 145 | Type: "RSA PRIVATE KEY", 146 | Bytes: x509.MarshalPKCS1PrivateKey(certPrivKey), 147 | }) 148 | 149 | serverCert, err := tls.X509KeyPair(certPEM.Bytes(), certPrivKeyPEM.Bytes()) 150 | if err != nil { 151 | return nil, nil, []byte{}, err 152 | } 153 | 154 | serverTLSConf = &tls.Config{ 155 | Certificates: []tls.Certificate{serverCert}, 156 | } 157 | 158 | certpool := x509.NewCertPool() 159 | certpool.AppendCertsFromPEM(caPEM.Bytes()) 160 | clientTLSConf = &tls.Config{ 161 | RootCAs: certpool, 162 | } 163 | 164 | caPEMBytes = caPEM.Bytes() 165 | 166 | return 167 | } 168 | -------------------------------------------------------------------------------- /mutatingwebhook/pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | namespace: testmutatingwebhook 5 | name: ubuntu 6 | labels: 7 | app: ubuntu 8 | spec: 9 | containers: 10 | - name: ubuntu 11 | image: ubuntu:latest 12 | command: ["/bin/sleep", "1d"] 13 | imagePullPolicy: IfNotPresent 14 | -------------------------------------------------------------------------------- /mutatingwebhook/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/tls" 5 | "encoding/base64" 6 | "encoding/json" 7 | "fmt" 8 | "net/http" 9 | ) 10 | 11 | //Server contains the functions handling server requests 12 | type Server struct { 13 | ServerTLSConf *tls.Config 14 | ClientTLSConf *tls.Config 15 | CaPEM []byte 16 | } 17 | 18 | func (s Server) getCA(w http.ResponseWriter, req *http.Request) { 19 | if len(s.CaPEM) == 0 { 20 | fmt.Fprintf(w, "No certificate found\n") 21 | return 22 | } 23 | 24 | // if base64 parameter is set, return in base64 format 25 | req.ParseForm() 26 | if _, hasParam := req.Form["base64"]; hasParam { 27 | fmt.Fprintf(w, string(base64.StdEncoding.EncodeToString(s.CaPEM))) 28 | return 29 | } 30 | 31 | fmt.Fprintf(w, string(s.CaPEM)) 32 | } 33 | 34 | func (s Server) postWebhook(w http.ResponseWriter, r *http.Request) { 35 | var request AdmissionReviewRequest 36 | err := json.NewDecoder(r.Body).Decode(&request) 37 | if err != nil { 38 | http.Error(w, fmt.Sprintf("JSON body in invalid format: %s\n", err.Error()), http.StatusBadRequest) 39 | return 40 | } 41 | if request.APIVersion != "admission.k8s.io/v1" || request.Kind != "AdmissionReview" { 42 | http.Error(w, fmt.Sprintf("wrong APIVersion or kind: %s - %s", request.APIVersion, request.Kind), http.StatusBadRequest) 43 | return 44 | 45 | } 46 | fmt.Printf("debug: %+v\n", request.Request) 47 | response := AdmissionReviewResponse{ 48 | APIVersion: "admission.k8s.io/v1", 49 | Kind: "AdmissionReview", 50 | Response: Response{ 51 | UID: request.Request.UID, 52 | Allowed: true, 53 | }, 54 | } 55 | 56 | // add label if we're creating a pod 57 | if request.Request.Kind.Group == "" && request.Request.Kind.Version == "v1" && request.Request.Kind.Kind == "Pod" && request.Request.Operation == "CREATE" { 58 | patch := `[{"op": "add", "path": "/metadata/labels/myExtraLabel", "value": "webhook-was-here"}]` 59 | patchEnc := base64.StdEncoding.EncodeToString([]byte(patch)) 60 | response.Response.PatchType = "JSONPatch" 61 | response.Response.Patch = patchEnc 62 | } 63 | 64 | out, err := json.Marshal(response) 65 | if err != nil { 66 | http.Error(w, fmt.Sprintf("JSON output marshal error: %s\n", err.Error()), http.StatusBadRequest) 67 | return 68 | } 69 | fmt.Printf("Got request, response: %s\n", string(out)) 70 | fmt.Fprintln(w, string(out)) 71 | } 72 | -------------------------------------------------------------------------------- /mutatingwebhook/types.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | //AdmissionReviewRespons for replies to incoming webhooks 4 | type AdmissionReviewResponse struct { 5 | APIVersion string `json:"apiVersion"` 6 | Kind string `json:"kind"` 7 | Response Response `json:"response"` 8 | } 9 | type Response struct { 10 | UID string `json:"uid"` 11 | Allowed bool `json:"allowed"` 12 | Patch string `json:"patch,omitempty"` 13 | PatchType string `json:"patchType,omitempty"` 14 | } 15 | 16 | //AdmissionReviewRequest for incoming webhooks 17 | type AdmissionReviewRequest struct { 18 | APIVersion string `json:"apiVersion"` 19 | Kind string `json:"kind"` 20 | Request Request `json:"request"` 21 | } 22 | type Kind struct { 23 | Group string `json:"group"` 24 | Version string `json:"version"` 25 | Kind string `json:"kind"` 26 | } 27 | type Resource struct { 28 | Group string `json:"group"` 29 | Version string `json:"version"` 30 | Resource string `json:"resource"` 31 | } 32 | type RequestKind struct { 33 | Group string `json:"group"` 34 | Version string `json:"version"` 35 | Kind string `json:"kind"` 36 | } 37 | type RequestResource struct { 38 | Group string `json:"group"` 39 | Version string `json:"version"` 40 | Resource string `json:"resource"` 41 | } 42 | type Extra struct { 43 | SomeKey []string `json:"some-key"` 44 | } 45 | type UserInfo struct { 46 | Username string `json:"username"` 47 | UID string `json:"uid"` 48 | Groups []string `json:"groups"` 49 | Extra Extra `json:"extra"` 50 | } 51 | type Object struct { 52 | APIVersion string `json:"apiVersion"` 53 | Kind string `json:"kind"` 54 | } 55 | type OldObject struct { 56 | APIVersion string `json:"apiVersion"` 57 | Kind string `json:"kind"` 58 | } 59 | type Options struct { 60 | APIVersion string `json:"apiVersion"` 61 | Kind string `json:"kind"` 62 | } 63 | type Request struct { 64 | UID string `json:"uid"` 65 | Kind Kind `json:"kind"` 66 | Resource Resource `json:"resource"` 67 | SubResource string `json:"subResource"` 68 | RequestKind RequestKind `json:"requestKind"` 69 | RequestResource RequestResource `json:"requestResource"` 70 | RequestSubResource string `json:"requestSubResource"` 71 | Name string `json:"name"` 72 | Namespace string `json:"namespace"` 73 | Operation string `json:"operation"` 74 | UserInfo UserInfo `json:"userInfo"` 75 | Object Object `json:"object"` 76 | OldObject OldObject `json:"oldObject"` 77 | Options Options `json:"options"` 78 | DryRun bool `json:"dryRun"` 79 | } 80 | -------------------------------------------------------------------------------- /mutatingwebhook/webhook.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: admissionregistration.k8s.io/v1 2 | kind: MutatingWebhookConfiguration 3 | metadata: 4 | name: "mymutatingwebhook.example.com" 5 | webhooks: 6 | - name: "mymutatingwebhook.example.com" 7 | namespaceSelector: 8 | matchLabels: 9 | webhook: enabled 10 | rules: 11 | - apiGroups: [""] 12 | apiVersions: ["v1"] 13 | operations: ["CREATE"] 14 | resources: ["pods"] 15 | clientConfig: 16 | service: 17 | namespace: "mutatingwebhook" 18 | name: "mutatingwebhook" 19 | path: "/webhook" 20 | caBundle: "cGxhY2Vob2xkZXIK" 21 | admissionReviewVersions: ["v1", "v1beta1"] 22 | sideEffects: None 23 | timeoutSeconds: 5 24 | --- 25 | apiVersion: v1 26 | kind: Namespace 27 | metadata: 28 | name: mutatingwebhook 29 | --- 30 | apiVersion: v1 31 | kind: Namespace 32 | metadata: 33 | name: testmutatingwebhook 34 | labels: 35 | webhook: enabled 36 | --- 37 | apiVersion: apps/v1 38 | kind: Deployment 39 | metadata: 40 | name: mutatingwebhook 41 | namespace: mutatingwebhook 42 | labels: 43 | app: mutatingwebhook 44 | spec: 45 | replicas: 1 46 | selector: 47 | matchLabels: 48 | app: mutatingwebhook 49 | template: 50 | metadata: 51 | labels: 52 | app: mutatingwebhook 53 | spec: 54 | containers: 55 | - name: mutatingwebhook 56 | image: wardviaene/mutatingwebhook-example 57 | ports: 58 | - containerPort: 8443 59 | --- 60 | apiVersion: v1 61 | kind: Service 62 | metadata: 63 | name: mutatingwebhook 64 | namespace: mutatingwebhook 65 | spec: 66 | selector: 67 | app: mutatingwebhook 68 | ports: 69 | - protocol: TCP 70 | port: 443 71 | targetPort: 8443 72 | -------------------------------------------------------------------------------- /pod-lifecycle/lifecycle.yaml: -------------------------------------------------------------------------------- 1 | kind: Deployment 2 | apiVersion: apps/v1 3 | metadata: 4 | name: lifecycle 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: lifecycle 10 | template: 11 | metadata: 12 | labels: 13 | app: lifecycle 14 | spec: 15 | initContainers: 16 | - name: init 17 | image: busybox 18 | command: ['sh', '-c', 'sleep 10'] 19 | containers: 20 | - name: lifecycle-container 21 | image: busybox 22 | command: ['sh', '-c', 'echo $(date +%s): Running >> /timing && echo "The app is running!" && /bin/sleep 120'] 23 | readinessProbe: 24 | exec: 25 | command: ['sh', '-c', 'echo $(date +%s): readinessProbe >> /timing'] 26 | initialDelaySeconds: 35 27 | livenessProbe: 28 | exec: 29 | command: ['sh', '-c', 'echo $(date +%s): livenessProbe >> /timing'] 30 | initialDelaySeconds: 35 31 | timeoutSeconds: 30 32 | lifecycle: 33 | postStart: 34 | exec: 35 | command: ['sh', '-c', 'echo $(date +%s): postStart >> /timing && sleep 10 && echo $(date +%s): end postStart >> /timing'] 36 | preStop: 37 | exec: 38 | command: ['sh', '-c', 'echo $(date +%s): preStop >> /timing && sleep 10'] 39 | -------------------------------------------------------------------------------- /pod-presets/README.md: -------------------------------------------------------------------------------- 1 | # PodPresets 2 | 3 | # Alpha status 4 | As long as the PodPresets is in alpha status, the following changes need to be made in kops: 5 | 6 | Add: 7 | ``` 8 | spec: 9 | kubeAPIServer: 10 | appendAdmissionPlugins: 11 | - PodPreset 12 | runtimeConfig: 13 | settings.k8s.io/v1alpha1: "true" 14 | ``` 15 | 16 | # running the demo 17 | First apply the PodPresets: 18 | ``` 19 | kubectl create -f pod-presets.yaml 20 | ``` 21 | 22 | Then run the deployments 23 | ``` 24 | kubectl create -f deployments.yaml 25 | ``` 26 | -------------------------------------------------------------------------------- /pod-presets/deployments.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: deployment-1 5 | spec: 6 | replicas: 3 7 | selector: 8 | matchLabels: 9 | app: myapp 10 | template: 11 | metadata: 12 | labels: 13 | app: myapp 14 | spec: 15 | containers: 16 | - name: k8s-demo 17 | image: wardviaene/k8s-demo 18 | ports: 19 | - name: nodejs-port 20 | containerPort: 3000 21 | --- 22 | apiVersion: apps/v1 23 | kind: Deployment 24 | metadata: 25 | name: deployment-2 26 | spec: 27 | replicas: 3 28 | selector: 29 | matchLabels: 30 | app: myapp-2 31 | template: 32 | metadata: 33 | labels: 34 | app: myapp-2 35 | spec: 36 | containers: 37 | - name: k8s-demo 38 | image: wardviaene/k8s-demo 39 | ports: 40 | - name: nodejs-port 41 | containerPort: 3000 42 | -------------------------------------------------------------------------------- /pod-presets/pod-presets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: settings.k8s.io/v1alpha1 # you might have to change this after PodPresets become stable 2 | kind: PodPreset 3 | metadata: 4 | name: share-credential 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: myapp 9 | env: 10 | - name: MY_SECRET 11 | value: "123456" 12 | volumeMounts: 13 | - mountPath: /share 14 | name: share-volume 15 | volumes: 16 | - name: share-volume 17 | emptyDir: {} 18 | -------------------------------------------------------------------------------- /pod-security-policies/README.md: -------------------------------------------------------------------------------- 1 | # Pod Security Setup 2 | 3 | ## Minikube 4 | 5 | ``` 6 | mkdir -p ~/.minikube/files/etc/kubernetes/addons/ 7 | cp initial-psp.yaml ~/.minikube/files/etc/kubernetes/addons/psp.yaml 8 | minikube start --extra-config=apiserver.enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,PodSecurityPolicy 9 | ``` 10 | 11 | ## Kops 12 | 13 | ``` 14 | kops edit cluster kubernetes.newtech.academy --state=s3://... 15 | ``` 16 | Add: 17 | ``` 18 | kubeAPIServer: 19 | appendAdmissionPlugins: 20 | - PodSecurityPolicy 21 | ``` 22 | -------------------------------------------------------------------------------- /pod-security-policies/bad-pod.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: hello-2 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: hello-2 10 | template: 11 | metadata: 12 | labels: 13 | app: hello-2 14 | spec: 15 | containers: 16 | - securityContext: 17 | runAsUser: 0 18 | name: hello-2 19 | image: wardviaene/http-echo 20 | env: 21 | - name: TEXT 22 | value: "hello world 2" 23 | ports: 24 | - name: http 25 | containerPort: 8080 26 | --- 27 | apiVersion: v1 28 | kind: Service 29 | metadata: 30 | name: hello-2 31 | labels: 32 | app: hello-2 33 | spec: 34 | selector: 35 | app: hello-2 36 | ports: 37 | - name: http 38 | port: 8080 39 | targetPort: 8080 40 | -------------------------------------------------------------------------------- /pod-security-policies/good-pod.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: hello 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: hello 10 | template: 11 | metadata: 12 | labels: 13 | app: hello 14 | spec: 15 | containers: 16 | - securityContext: 17 | runAsUser: 100 18 | name: hello 19 | image: wardviaene/http-echo 20 | env: 21 | - name: TEXT 22 | value: hello world 23 | ports: 24 | - name: http 25 | containerPort: 8080 26 | --- 27 | apiVersion: v1 28 | kind: Service 29 | metadata: 30 | name: hello 31 | labels: 32 | app: hello 33 | spec: 34 | selector: 35 | app: hello 36 | ports: 37 | - name: http 38 | port: 8080 39 | targetPort: 8080 40 | -------------------------------------------------------------------------------- /pod-security-policies/initial-psp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: policy/v1beta1 3 | kind: PodSecurityPolicy 4 | metadata: 5 | name: privileged 6 | annotations: 7 | seccomp.security.alpha.kubernetes.io/allowedProfileNames: "*" 8 | labels: 9 | addonmanager.kubernetes.io/mode: EnsureExists 10 | spec: 11 | privileged: true 12 | allowPrivilegeEscalation: true 13 | allowedCapabilities: 14 | - "*" 15 | volumes: 16 | - "*" 17 | hostNetwork: true 18 | hostPorts: 19 | - min: 0 20 | max: 65535 21 | hostIPC: true 22 | hostPID: true 23 | runAsUser: 24 | rule: 'RunAsAny' 25 | seLinux: 26 | rule: 'RunAsAny' 27 | supplementalGroups: 28 | rule: 'RunAsAny' 29 | fsGroup: 30 | rule: 'RunAsAny' 31 | --- 32 | apiVersion: policy/v1beta1 33 | kind: PodSecurityPolicy 34 | metadata: 35 | name: restricted 36 | labels: 37 | addonmanager.kubernetes.io/mode: EnsureExists 38 | spec: 39 | privileged: false 40 | allowPrivilegeEscalation: false 41 | requiredDropCapabilities: 42 | - ALL 43 | volumes: 44 | - 'configMap' 45 | - 'emptyDir' 46 | - 'projected' 47 | - 'secret' 48 | - 'downwardAPI' 49 | - 'persistentVolumeClaim' 50 | hostNetwork: false 51 | hostIPC: false 52 | hostPID: false 53 | runAsUser: 54 | rule: 'MustRunAsNonRoot' 55 | seLinux: 56 | rule: 'RunAsAny' 57 | supplementalGroups: 58 | rule: 'MustRunAs' 59 | ranges: 60 | # Forbid adding the root group. 61 | - min: 1 62 | max: 65535 63 | fsGroup: 64 | rule: 'MustRunAs' 65 | ranges: 66 | # Forbid adding the root group. 67 | - min: 1 68 | max: 65535 69 | readOnlyRootFilesystem: false 70 | --- 71 | apiVersion: rbac.authorization.k8s.io/v1 72 | kind: ClusterRole 73 | metadata: 74 | name: psp:privileged 75 | labels: 76 | addonmanager.kubernetes.io/mode: EnsureExists 77 | rules: 78 | - apiGroups: ['policy'] 79 | resources: ['podsecuritypolicies'] 80 | verbs: ['use'] 81 | resourceNames: 82 | - privileged 83 | --- 84 | apiVersion: rbac.authorization.k8s.io/v1 85 | kind: ClusterRole 86 | metadata: 87 | name: psp:restricted 88 | labels: 89 | addonmanager.kubernetes.io/mode: EnsureExists 90 | rules: 91 | - apiGroups: ['policy'] 92 | resources: ['podsecuritypolicies'] 93 | verbs: ['use'] 94 | resourceNames: 95 | - restricted 96 | --- 97 | apiVersion: rbac.authorization.k8s.io/v1 98 | kind: ClusterRoleBinding 99 | metadata: 100 | name: default:restricted 101 | labels: 102 | addonmanager.kubernetes.io/mode: EnsureExists 103 | roleRef: 104 | apiGroup: rbac.authorization.k8s.io 105 | kind: ClusterRole 106 | name: psp:restricted 107 | subjects: 108 | - kind: Group 109 | name: system:authenticated 110 | apiGroup: rbac.authorization.k8s.io 111 | --- 112 | apiVersion: rbac.authorization.k8s.io/v1 113 | kind: RoleBinding 114 | metadata: 115 | name: default:privileged 116 | namespace: kube-system 117 | labels: 118 | addonmanager.kubernetes.io/mode: EnsureExists 119 | roleRef: 120 | apiGroup: rbac.authorization.k8s.io 121 | kind: ClusterRole 122 | name: psp:privileged 123 | subjects: 124 | - kind: Group 125 | name: system:masters 126 | apiGroup: rbac.authorization.k8s.io 127 | - kind: Group 128 | name: system:nodes 129 | apiGroup: rbac.authorization.k8s.io 130 | - kind: Group 131 | name: system:serviceaccounts:kube-system 132 | apiGroup: rbac.authorization.k8s.io 133 | -------------------------------------------------------------------------------- /pod-security-policies/restricted-psp.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: policy/v1beta1 2 | kind: PodSecurityPolicy 3 | metadata: 4 | name: restricted 5 | spec: 6 | privileged: false 7 | allowPrivilegeEscalation: false 8 | requiredDropCapabilities: 9 | - ALL 10 | volumes: 11 | - 'configMap' 12 | - 'emptyDir' 13 | - 'projected' 14 | - 'secret' 15 | - 'downwardAPI' 16 | - 'persistentVolumeClaim' 17 | hostNetwork: false 18 | hostIPC: false 19 | hostPID: false 20 | runAsUser: 21 | rule: 'MustRunAsNonRoot' 22 | seLinux: 23 | rule: 'RunAsAny' 24 | supplementalGroups: 25 | rule: 'MustRunAs' 26 | ranges: 27 | # Forbid adding the root group. 28 | - min: 1 29 | max: 65535 30 | fsGroup: 31 | rule: 'MustRunAs' 32 | ranges: 33 | # Forbid adding the root group. 34 | - min: 1 35 | max: 65535 36 | readOnlyRootFilesystem: false 37 | --- 38 | apiVersion: rbac.authorization.k8s.io/v1 39 | kind: ClusterRole 40 | metadata: 41 | name: psp:restricted 42 | rules: 43 | - apiGroups: ['policy'] 44 | resources: ['podsecuritypolicies'] 45 | verbs: ['use'] 46 | resourceNames: 47 | - restricted 48 | --- 49 | apiVersion: rbac.authorization.k8s.io/v1 50 | kind: ClusterRoleBinding 51 | metadata: 52 | name: default:restricted 53 | roleRef: 54 | apiGroup: rbac.authorization.k8s.io 55 | kind: ClusterRole 56 | name: psp:restricted 57 | subjects: 58 | - kind: Group 59 | name: system:authenticated 60 | apiGroup: rbac.authorization.k8s.io 61 | -------------------------------------------------------------------------------- /pod-security-policies/serviceaccount.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: test-account 5 | --- 6 | apiVersion: rbac.authorization.k8s.io/v1 7 | kind: ClusterRole 8 | metadata: 9 | name: restricted-psp 10 | rules: 11 | - apiGroups: ['policy'] 12 | resources: ['podsecuritypolicies'] 13 | verbs: ['use'] 14 | resourceNames: 15 | - restricted 16 | --- 17 | apiVersion: rbac.authorization.k8s.io/v1 18 | kind: ClusterRoleBinding 19 | metadata: 20 | name: test-role 21 | roleRef: 22 | apiGroup: rbac.authorization.k8s.io 23 | kind: ClusterRole 24 | name: edit 25 | subjects: 26 | - kind: ServiceAccount 27 | name: test-account 28 | namespace: default 29 | --- 30 | apiVersion: rbac.authorization.k8s.io/v1 31 | kind: ClusterRoleBinding 32 | metadata: 33 | name: test-role-restricted-psp 34 | roleRef: 35 | apiGroup: rbac.authorization.k8s.io 36 | kind: ClusterRole 37 | name: restricted-psp 38 | subjects: 39 | - kind: ServiceAccount 40 | name: test-account 41 | namespace: default 42 | --- 43 | -------------------------------------------------------------------------------- /postgres-operator/README.md: -------------------------------------------------------------------------------- 1 | # Files 2 | There is no quickstart-for-gke.sh anymore. This has been replaced by quickstart.sh. 3 | 4 | # setup storage 5 | ``` 6 | kubectl create -f storage.yml 7 | ``` 8 | 9 | # setup Operator 10 | ``` 11 | ./quickstart.sh 12 | ``` 13 | 14 | # Create cluster 15 | 16 | ``` 17 | kubectl apply -f postgres-example.yaml 18 | ``` 19 | 20 | # Show cluster pods 21 | 22 | ``` 23 | kubectl get pods -n postgres-operator 24 | ``` 25 | 26 | # show secrets 27 | ``` 28 | kubectl get secrets -n postgres-operator hippo-pguser-hippo -o yaml |grep user |cut -d ':' -f2 |cut -d ' ' -f2 |base64 --decode 29 | kubectl get secrets -n postgres-operator hippo-pguser-hippo -o yaml |grep password |cut -d ':' -f2 |cut -d ' ' -f2 |base64 --decode 30 | kubectl get secrets -n postgres-operator hippo-pguser-hippo -o yaml |grep host |cut -d ':' -f2 |cut -d ' ' -f2 |base64 --decode 31 | ``` 32 | 33 | # connect to psql 34 | 35 | Use user, password, and host from previous step. 36 | 37 | ``` 38 | kubectl run -n postgres-operator -it --rm --image=postgres:10.4 psql-client -- psql -h hippo-primary.postgres-operator.svc -U hippo -W postgres 39 | ``` 40 | 41 | Note: When you see 'If you don't see a command prompt, try pressing enter.', you can enter the password 42 | 43 | 44 | # Create read replic 45 | Once you add replicas: 2 to the yaml definition, and you apply it, you'll see the new replica being spun up 46 | ``` 47 | kubectl apply -f postgres-example-scale.yaml 48 | kubectl get pods -n postgres-operator 49 | ``` 50 | 51 | # Shutdown cluster 52 | ``` 53 | kubectl patch postgrescluster/hippo -n postgres-operator --type merge --patch '{"spec":{"shutdown": true}}' 54 | ``` 55 | -------------------------------------------------------------------------------- /postgres-operator/postgres-example-scale.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: hippo 5 | namespace: postgres-operator 6 | spec: 7 | image: registry.developers.crunchydata.com/crunchydata/crunchy-postgres:centos8-13.5-0 8 | postgresVersion: 13 9 | instances: 10 | - name: instance1 11 | replicas: 2 12 | dataVolumeClaimSpec: 13 | accessModes: 14 | - "ReadWriteOnce" 15 | resources: 16 | requests: 17 | storage: 1Gi 18 | backups: 19 | pgbackrest: 20 | image: registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:centos8-2.36-0 21 | repos: 22 | - name: repo1 23 | volume: 24 | volumeClaimSpec: 25 | accessModes: 26 | - "ReadWriteOnce" 27 | resources: 28 | requests: 29 | storage: 1Gi 30 | -------------------------------------------------------------------------------- /postgres-operator/postgres-example.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: postgres-operator.crunchydata.com/v1beta1 2 | kind: PostgresCluster 3 | metadata: 4 | name: hippo 5 | namespace: postgres-operator 6 | spec: 7 | image: registry.developers.crunchydata.com/crunchydata/crunchy-postgres:centos8-13.5-0 8 | postgresVersion: 13 9 | instances: 10 | - name: instance1 11 | dataVolumeClaimSpec: 12 | accessModes: 13 | - "ReadWriteOnce" 14 | resources: 15 | requests: 16 | storage: 1Gi 17 | backups: 18 | pgbackrest: 19 | image: registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:centos8-2.36-0 20 | repos: 21 | - name: repo1 22 | volume: 23 | volumeClaimSpec: 24 | accessModes: 25 | - "ReadWriteOnce" 26 | resources: 27 | requests: 28 | storage: 1Gi 29 | -------------------------------------------------------------------------------- /postgres-operator/quickstart.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "This script replaces quickstart-for-gke.sh" 3 | echo "" 4 | echo "This script will:" 5 | echo "- Create the pgo namespace" 6 | echo "- Apply postgres-operator.yml" 7 | echo "- install the client" 8 | echo "" 9 | wget https://github.com/CrunchyData/postgres-operator-examples/archive/refs/heads/main.zip 10 | unzip main.zip 11 | kubectl apply -k postgres-operator-examples-main/kustomize/install 12 | echo "wait until pod is ready" 13 | sleep 15 14 | kubectl -n postgres-operator wait pods --selector=postgres-operator.crunchydata.com/control-plane=postgres-operator --field-selector=status.phase=Running --for=condition=ready 15 | 16 | echo "pgo 4 is not compatible anymore with newer kubernetes cluster. PGO 5 has been installed. Check the README.md in this directory for the commands to launch a postgres cluster" 17 | -------------------------------------------------------------------------------- /postgres-operator/set-path.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 'export PATH=$PATH:~/.pgo/pgo/' >> ~/.bashrc 3 | echo 'export PGOUSER="${HOME?}/.pgo/pgo/pgouser"' >> ~/.bashrc 4 | echo 'export PGO_CA_CERT="${HOME?}/.pgo/pgo/client.crt"' >> ~/.bashrc 5 | echo 'export PGO_CLIENT_CERT="${HOME?}/.pgo/pgo/client.crt"' >> ~/.bashrc 6 | echo 'export PGO_CLIENT_KEY="${HOME?}/.pgo/pgo/client.key"' >> ~/.bashrc 7 | echo 'export PGO_APISERVER_URL='https://127.0.0.1:8443'' >> ~/.bashrc 8 | echo 'export PGO_NAMESPACE=pgo' >> ~/.bashrc 9 | 10 | -------------------------------------------------------------------------------- /postgres-operator/storage.yml: -------------------------------------------------------------------------------- 1 | kind: StorageClass 2 | apiVersion: storage.k8s.io/v1 3 | metadata: 4 | name: standard 5 | provisioner: kubernetes.io/aws-ebs 6 | parameters: 7 | type: gp2 8 | zone: eu-west-1a 9 | -------------------------------------------------------------------------------- /replication-controller/helloworld-repl-controller.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ReplicationController 3 | metadata: 4 | name: helloworld-controller 5 | spec: 6 | replicas: 2 7 | selector: 8 | app: helloworld 9 | template: 10 | metadata: 11 | labels: 12 | app: helloworld 13 | spec: 14 | containers: 15 | - name: k8s-demo 16 | image: wardviaene/k8s-demo 17 | ports: 18 | - name: nodejs-port 19 | containerPort: 3000 20 | -------------------------------------------------------------------------------- /resourcequotas/defaults.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: LimitRange 3 | metadata: 4 | name: limits 5 | namespace: myspace 6 | spec: 7 | limits: 8 | - default: 9 | cpu: 200m 10 | memory: 512Mi 11 | defaultRequest: 12 | cpu: 100m 13 | memory: 256Mi 14 | type: Container 15 | -------------------------------------------------------------------------------- /resourcequotas/helloworld-no-quotas.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: helloworld-deployment 5 | namespace: myspace 6 | spec: 7 | replicas: 3 8 | selector: 9 | matchLabels: 10 | app: helloworld 11 | template: 12 | metadata: 13 | labels: 14 | app: helloworld 15 | spec: 16 | containers: 17 | - name: k8s-demo 18 | image: wardviaene/k8s-demo 19 | ports: 20 | - name: nodejs-port 21 | containerPort: 3000 22 | -------------------------------------------------------------------------------- /resourcequotas/helloworld-with-quotas.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: helloworld-deployment 5 | namespace: myspace 6 | spec: 7 | replicas: 3 8 | selector: 9 | matchLabels: 10 | app: helloworld 11 | template: 12 | metadata: 13 | labels: 14 | app: helloworld 15 | spec: 16 | containers: 17 | - name: k8s-demo 18 | image: wardviaene/k8s-demo 19 | ports: 20 | - name: nodejs-port 21 | containerPort: 3000 22 | resources: 23 | requests: 24 | cpu: 200m 25 | memory: 0.5Gi 26 | limits: 27 | cpu: 400m 28 | memory: 1Gi 29 | -------------------------------------------------------------------------------- /resourcequotas/resourcequota.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: myspace 5 | --- 6 | apiVersion: v1 7 | kind: ResourceQuota 8 | metadata: 9 | name: compute-quota 10 | namespace: myspace 11 | spec: 12 | hard: 13 | requests.cpu: "1" 14 | requests.memory: 1Gi 15 | limits.cpu: "2" 16 | limits.memory: 2Gi 17 | --- 18 | apiVersion: v1 19 | kind: ResourceQuota 20 | metadata: 21 | name: object-quota 22 | namespace: myspace 23 | spec: 24 | hard: 25 | configmaps: "10" 26 | persistentvolumeclaims: "4" 27 | replicationcontrollers: "20" 28 | secrets: "10" 29 | services: "10" 30 | services.loadbalancers: "2" 31 | -------------------------------------------------------------------------------- /service-discovery/database-service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: database-service 5 | spec: 6 | ports: 7 | - port: 3306 8 | protocol: TCP 9 | selector: 10 | app: database 11 | type: NodePort 12 | -------------------------------------------------------------------------------- /service-discovery/database.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: database 5 | labels: 6 | app: database 7 | spec: 8 | containers: 9 | - name: mysql 10 | image: mysql:8 11 | ports: 12 | - name: mysql-port 13 | containerPort: 3306 14 | env: 15 | - name: MYSQL_ROOT_PASSWORD 16 | valueFrom: 17 | secretKeyRef: 18 | name: helloworld-secrets 19 | key: rootPassword 20 | - name: MYSQL_USER 21 | valueFrom: 22 | secretKeyRef: 23 | name: helloworld-secrets 24 | key: username 25 | - name: MYSQL_PASSWORD 26 | valueFrom: 27 | secretKeyRef: 28 | name: helloworld-secrets 29 | key: password 30 | - name: MYSQL_DATABASE 31 | valueFrom: 32 | secretKeyRef: 33 | name: helloworld-secrets 34 | key: database 35 | -------------------------------------------------------------------------------- /service-discovery/helloworld-db-service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: helloworld-db-service 5 | spec: 6 | ports: 7 | - port: 3000 8 | protocol: TCP 9 | selector: 10 | app: helloworld-db 11 | type: NodePort 12 | -------------------------------------------------------------------------------- /service-discovery/helloworld-db.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: helloworld-deployment 5 | spec: 6 | replicas: 3 7 | selector: 8 | matchLabels: 9 | app: helloworld-db 10 | template: 11 | metadata: 12 | labels: 13 | app: helloworld-db 14 | spec: 15 | containers: 16 | - name: k8s-demo 17 | image: wardviaene/k8s-demo 18 | command: ["node", "index-db.js"] 19 | ports: 20 | - name: nodejs-port 21 | containerPort: 3000 22 | env: 23 | - name: MYSQL_HOST 24 | value: database-service 25 | - name: MYSQL_USER 26 | value: root 27 | - name: MYSQL_PASSWORD 28 | valueFrom: 29 | secretKeyRef: 30 | name: helloworld-secrets 31 | key: rootPassword 32 | - name: MYSQL_DATABASE 33 | valueFrom: 34 | secretKeyRef: 35 | name: helloworld-secrets 36 | key: database 37 | -------------------------------------------------------------------------------- /service-discovery/secrets.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: helloworld-secrets 5 | type: Opaque 6 | data: 7 | username: aGVsbG93b3JsZA== 8 | password: cGFzc3dvcmQ= 9 | rootPassword: cm9vdHBhc3N3b3Jk 10 | database: aGVsbG93b3JsZA== 11 | -------------------------------------------------------------------------------- /skaffold-demo/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.12.9-alpine3.10 as builder 2 | COPY main.go . 3 | RUN go build -o /app main.go 4 | 5 | FROM alpine:3.10 6 | CMD ["./app"] 7 | COPY --from=builder /app . 8 | -------------------------------------------------------------------------------- /skaffold-demo/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/wardviaene/kubernetes-course/skaffold-demo 2 | 3 | go 1.13 4 | -------------------------------------------------------------------------------- /skaffold-demo/k8s-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: skaffold-demo 5 | labels: 6 | app: skaffold-demo 7 | spec: 8 | containers: 9 | - name: skaffold-demo 10 | image: wardviaene/skaffold-demo 11 | --- 12 | apiVersion: v1 13 | kind: Service 14 | metadata: 15 | name: skaffold-demo 16 | spec: 17 | selector: 18 | app: skaffold-demo 19 | type: LoadBalancer 20 | ports: 21 | - protocol: TCP 22 | port: 80 23 | targetPort: 8080 24 | -------------------------------------------------------------------------------- /skaffold-demo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | func main() { 9 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 10 | fmt.Fprintf(w, "hello world") 11 | }) 12 | 13 | fmt.Printf("Listening on port 8080\n") 14 | http.ListenAndServe(":8080", nil) 15 | 16 | } 17 | -------------------------------------------------------------------------------- /skaffold-demo/skaffold.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: skaffold/v1 2 | kind: Config 3 | build: 4 | artifacts: 5 | - image: wardviaene/skaffold-demo 6 | deploy: 7 | kubectl: 8 | manifests: 9 | - k8s-* 10 | -------------------------------------------------------------------------------- /statefulset/cassandra.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: cassandra 5 | labels: 6 | app: cassandra 7 | spec: 8 | serviceName: cassandra 9 | replicas: 3 10 | selector: 11 | matchLabels: 12 | app: cassandra 13 | template: 14 | metadata: 15 | labels: 16 | app: cassandra 17 | spec: 18 | terminationGracePeriodSeconds: 1800 19 | containers: 20 | - name: cassandra 21 | image: gcr.io/google-samples/cassandra:v13 22 | imagePullPolicy: Always 23 | ports: 24 | - containerPort: 7000 25 | name: intra-node 26 | - containerPort: 7001 27 | name: tls-intra-node 28 | - containerPort: 7199 29 | name: jmx 30 | - containerPort: 9042 31 | name: cql 32 | resources: 33 | limits: 34 | cpu: "500m" 35 | memory: 1Gi 36 | requests: 37 | cpu: "500m" 38 | memory: 1Gi 39 | securityContext: 40 | capabilities: 41 | add: 42 | - IPC_LOCK 43 | lifecycle: 44 | preStop: 45 | exec: 46 | command: 47 | - /bin/sh 48 | - -c 49 | - nodetool drain 50 | env: 51 | - name: MAX_HEAP_SIZE 52 | value: 512M 53 | - name: HEAP_NEWSIZE 54 | value: 100M 55 | - name: CASSANDRA_SEEDS 56 | value: "cassandra-0.cassandra.default.svc.cluster.local" 57 | - name: CASSANDRA_CLUSTER_NAME 58 | value: "K8Demo" 59 | - name: CASSANDRA_DC 60 | value: "DC1-K8Demo" 61 | - name: CASSANDRA_RACK 62 | value: "Rack1-K8Demo" 63 | - name: POD_IP 64 | valueFrom: 65 | fieldRef: 66 | fieldPath: status.podIP 67 | readinessProbe: 68 | exec: 69 | command: 70 | - /bin/bash 71 | - -c 72 | - /ready-probe.sh 73 | initialDelaySeconds: 15 74 | timeoutSeconds: 5 75 | # These volume mounts are persistent. They are like inline claims, 76 | # but not exactly because the names need to match exactly one of 77 | # the stateful pod volumes. 78 | volumeMounts: 79 | - name: cassandra-data 80 | mountPath: /cassandra_data 81 | # These are converted to volume claims by the controller 82 | # and mounted at the paths mentioned above. 83 | # do not use these in production until ssd GCEPersistentDisk or other ssd pd 84 | volumeClaimTemplates: 85 | - metadata: 86 | name: cassandra-data 87 | spec: 88 | accessModes: [ "ReadWriteOnce" ] 89 | storageClassName: standard 90 | resources: 91 | requests: 92 | storage: 8Gi 93 | --- 94 | kind: StorageClass 95 | apiVersion: storage.k8s.io/v1beta1 96 | metadata: 97 | name: standard 98 | provisioner: kubernetes.io/aws-ebs 99 | parameters: 100 | type: gp2 101 | zone: eu-west-1a 102 | --- 103 | apiVersion: v1 104 | kind: Service 105 | metadata: 106 | labels: 107 | app: cassandra 108 | name: cassandra 109 | spec: 110 | clusterIP: None 111 | ports: 112 | - port: 9042 113 | selector: 114 | app: cassandra 115 | -------------------------------------------------------------------------------- /tolerations/README.md: -------------------------------------------------------------------------------- 1 | # Taint and Tolerations 2 | 3 | # Taint a node 4 | ``` 5 | kubectl taint nodes NODE-NAME type=specialnode:NoSchedule 6 | ``` 7 | 8 | # Taint a node with NoExecute 9 | ``` 10 | kubectl taint nodes NODE-NAME testkey=testvalue:NoExecute 11 | ``` 12 | -------------------------------------------------------------------------------- /tolerations/tolerations.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: tolerations-1 5 | spec: 6 | replicas: 3 7 | selector: 8 | matchLabels: 9 | app: tolerations-1 10 | template: 11 | metadata: 12 | labels: 13 | app: tolerations-1 14 | spec: 15 | containers: 16 | - name: k8s-demo 17 | image: wardviaene/k8s-demo 18 | ports: 19 | - name: nodejs-port 20 | containerPort: 3000 21 | --- 22 | apiVersion: apps/v1 23 | kind: Deployment 24 | metadata: 25 | name: tolerations-2 26 | spec: 27 | replicas: 3 28 | selector: 29 | matchLabels: 30 | app: tolerations-2 31 | template: 32 | metadata: 33 | labels: 34 | app: tolerations-2 35 | spec: 36 | tolerations: 37 | - key: "type" 38 | operator: "Equal" 39 | value: "specialnode" 40 | effect: "NoSchedule" 41 | containers: 42 | - name: k8s-demo 43 | image: wardviaene/k8s-demo 44 | ports: 45 | - name: nodejs-port 46 | containerPort: 3000 47 | -------------------------------------------------------------------------------- /users/README.md: -------------------------------------------------------------------------------- 1 | ## Retrieve keys from kops 2 | ``` 3 | aws s3 sync s3://kops-state-b429b/kubernetes.newtech.academy/pki/private/ca/ ca-key 4 | aws s3 sync s3://kops-state-b429b/kubernetes.newtech.academy/pki/issued/ca/ ca-crt 5 | mv ca-key/*.key ca.key 6 | mv ca-crt/*.crt ca.crt 7 | ``` 8 | ## Create new user 9 | ``` 10 | sudo apt install openssl 11 | openssl genrsa -out edward.pem 2048 12 | openssl req -new -key edward.pem -out edward-csr.pem -subj "/CN=edward/O=myteam/" 13 | openssl x509 -req -in edward-csr.pem -CA ca.crt -CAkey ca.key -CAcreateserial -out edward.crt -days 10000 14 | ``` 15 | 16 | ## add new context 17 | ``` 18 | kubectl config set-credentials edward --client-certificate=edward.crt --client-key=edward.pem 19 | kubectl config set-context edward --cluster=kubernetes.newtech.academy --user edward 20 | ``` 21 | -------------------------------------------------------------------------------- /users/admin-user.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: admin-user 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: cluster-admin 9 | subjects: 10 | - kind: User 11 | name: "edward" 12 | apiGroup: rbac.authorization.k8s.io 13 | -------------------------------------------------------------------------------- /users/user.yaml: -------------------------------------------------------------------------------- 1 | kind: Role 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | metadata: 4 | namespace: default 5 | name: pod-writer 6 | rules: 7 | - apiGroups: [""] 8 | resources: ["pods"] 9 | verbs: ["get", "watch", "list", "create", "update", "patch", "delete"] 10 | - apiGroups: ["extensions", "apps"] 11 | resources: ["deployments"] 12 | verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] 13 | --- 14 | kind: RoleBinding 15 | apiVersion: rbac.authorization.k8s.io/v1beta1 16 | metadata: 17 | name: write-pods 18 | namespace: default 19 | subjects: 20 | - kind: User 21 | name: edward 22 | apiGroup: rbac.authorization.k8s.io 23 | roleRef: 24 | kind: Role 25 | name: pod-writer 26 | apiGroup: rbac.authorization.k8s.io 27 | -------------------------------------------------------------------------------- /volumes/README.md: -------------------------------------------------------------------------------- 1 | # Create volumes 2 | 3 | ## Create Volume in AWS 4 | 5 | ``` 6 | aws ec2 create-volume --size 10 --region your-region --availability-zone your-zone --volume-type gp2 --tag-specifications 'ResourceType=volume, Tags=[{Key= KubernetesCluster, Value=kubernetes.domain.tld}]' 7 | ``` 8 | -------------------------------------------------------------------------------- /volumes/helloworld-with-volume.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: helloworld-deployment 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: helloworld 10 | template: 11 | metadata: 12 | labels: 13 | app: helloworld 14 | spec: 15 | containers: 16 | - name: k8s-demo 17 | image: wardviaene/k8s-demo 18 | ports: 19 | - name: nodejs-port 20 | containerPort: 3000 21 | volumeMounts: 22 | - mountPath: /myvol 23 | name: myvolume 24 | volumes: 25 | - name: myvolume 26 | awsElasticBlockStore: 27 | volumeID: # insert AWS EBS volumeID here 28 | -------------------------------------------------------------------------------- /wordpress-volumes/pv-claim.yml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolumeClaim 2 | apiVersion: v1 3 | metadata: 4 | name: db-storage 5 | annotations: 6 | volume.beta.kubernetes.io/storage-class: "standard" 7 | spec: 8 | accessModes: 9 | - ReadWriteOnce 10 | resources: 11 | requests: 12 | storage: 8Gi 13 | -------------------------------------------------------------------------------- /wordpress-volumes/storage.yml: -------------------------------------------------------------------------------- 1 | kind: StorageClass 2 | apiVersion: storage.k8s.io/v1 3 | metadata: 4 | name: standard 5 | provisioner: kubernetes.io/aws-ebs 6 | parameters: 7 | type: gp2 8 | zone: eu-west-1a 9 | -------------------------------------------------------------------------------- /wordpress-volumes/wordpress-db-service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: wordpress-db 5 | spec: 6 | ports: 7 | - port: 3306 8 | protocol: TCP 9 | selector: 10 | app: wordpress-db 11 | type: NodePort 12 | -------------------------------------------------------------------------------- /wordpress-volumes/wordpress-db.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ReplicationController 3 | metadata: 4 | name: wordpress-db 5 | spec: 6 | replicas: 1 7 | selector: 8 | app: wordpress-db 9 | template: 10 | metadata: 11 | name: wordpress-db 12 | labels: 13 | app: wordpress-db 14 | spec: 15 | containers: 16 | - name: mysql 17 | image: mysql:8 18 | args: 19 | - "--ignore-db-dir=lost+found" 20 | ports: 21 | - name: mysql-port 22 | containerPort: 3306 23 | env: 24 | - name: MYSQL_DATABASE 25 | value: wordpress 26 | - name: MYSQL_ROOT_PASSWORD 27 | valueFrom: 28 | secretKeyRef: 29 | name: wordpress-secrets 30 | key: db-password 31 | volumeMounts: 32 | - mountPath: "/var/lib/mysql" 33 | name: mysql-storage 34 | volumes: 35 | - name: mysql-storage 36 | persistentVolumeClaim: 37 | claimName: db-storage 38 | -------------------------------------------------------------------------------- /wordpress-volumes/wordpress-secrets.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: wordpress-secrets 5 | type: Opaque 6 | data: 7 | db-password: cGFzc3dvcmQ= 8 | # random sha1 strings - change all these lines 9 | authkey: MTQ3ZDVhMTIzYmU1ZTRiMWQ1NzUyOWFlNWE2YzRjY2FhMDkyZGQ4OA== 10 | loggedinkey: MTQ3ZDVhMTIzYmU1ZTRiMWQ1NzUyOWFlNWE2YzRjY2FhMDkyZGQ4OQ== 11 | secureauthkey: MTQ3ZDVhMTIzYmU1ZTRiMWQ1NzUyOWFlNWE2YzRjY2FhMDkyZGQ5MQ== 12 | noncekey: MTQ3ZDVhMTIzYmU1ZTRiMWQ1NzUyOWFlNWE2YzRjY2FhMDkyZGQ5MA== 13 | authsalt: MTQ3ZDVhMTIzYmU1ZTRiMWQ1NzUyOWFlNWE2YzRjY2FhMDkyZGQ5Mg== 14 | secureauthsalt: MTQ3ZDVhMTIzYmU1ZTRiMWQ1NzUyOWFlNWE2YzRjY2FhMDkyZGQ5Mw== 15 | loggedinsalt: MTQ3ZDVhMTIzYmU1ZTRiMWQ1NzUyOWFlNWE2YzRjY2FhMDkyZGQ5NA== 16 | noncesalt: MTQ3ZDVhMTIzYmU1ZTRiMWQ1NzUyOWFlNWE2YzRjY2FhMDkyZGQ5NQ== 17 | -------------------------------------------------------------------------------- /wordpress-volumes/wordpress-web-service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: wordpress 5 | spec: 6 | ports: 7 | - port: 80 8 | targetPort: http-port 9 | protocol: TCP 10 | selector: 11 | app: wordpress 12 | type: LoadBalancer 13 | -------------------------------------------------------------------------------- /wordpress-volumes/wordpress-web.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: wordpress-deployment 5 | spec: 6 | replicas: 2 7 | selector: 8 | matchLabels: 9 | app: wordpress 10 | template: 11 | metadata: 12 | labels: 13 | app: wordpress 14 | spec: 15 | containers: 16 | - name: wordpress 17 | image: wordpress:6-php8.0 18 | # uncomment to fix perm issue, see also https://github.com/kubernetes/kubernetes/issues/2630 19 | # command: ['bash', '-c', 'mkdir -p /var/www/html/wp-content/uploads; chown www-data:www-data /var/www/html/wp-content/uploads && docker-entrypoint.sh apache2-foreground'] 20 | ports: 21 | - name: http-port 22 | containerPort: 80 23 | env: 24 | - name: WORDPRESS_DB_USER 25 | value: root 26 | - name: WORDPRESS_DB_NAME 27 | value: wordpress 28 | - name: WORDPRESS_DB_PASSWORD 29 | valueFrom: 30 | secretKeyRef: 31 | name: wordpress-secrets 32 | key: db-password 33 | - name: WORDPRESS_AUTH_KEY 34 | valueFrom: 35 | secretKeyRef: 36 | name: wordpress-secrets 37 | key: authkey 38 | - name: WORDPRESS_LOGGED_IN_KEY 39 | valueFrom: 40 | secretKeyRef: 41 | name: wordpress-secrets 42 | key: loggedinkey 43 | - name: WORDPRESS_SECURE_AUTH_KEY 44 | valueFrom: 45 | secretKeyRef: 46 | name: wordpress-secrets 47 | key: secureauthkey 48 | - name: WORDPRESS_NONCE_KEY 49 | valueFrom: 50 | secretKeyRef: 51 | name: wordpress-secrets 52 | key: noncekey 53 | - name: WORDPRESS_AUTH_SALT 54 | valueFrom: 55 | secretKeyRef: 56 | name: wordpress-secrets 57 | key: authsalt 58 | - name: WORDPRESS_SECURE_AUTH_SALT 59 | valueFrom: 60 | secretKeyRef: 61 | name: wordpress-secrets 62 | key: secureauthsalt 63 | - name: WORDPRESS_LOGGED_IN_SALT 64 | valueFrom: 65 | secretKeyRef: 66 | name: wordpress-secrets 67 | key: loggedinsalt 68 | - name: WORDPRESS_NONCE_SALT 69 | valueFrom: 70 | secretKeyRef: 71 | name: wordpress-secrets 72 | key: noncesalt 73 | - name: WORDPRESS_DB_HOST 74 | value: wordpress-db 75 | volumeMounts: 76 | - mountPath: /var/www/html/wp-content/uploads 77 | name: uploads 78 | volumes: 79 | - name: uploads 80 | nfs: 81 | server: eu-west-1a.fs-5714e89e.efs.eu-west-1.amazonaws.com 82 | path: / 83 | -------------------------------------------------------------------------------- /wordpress/wordpress-secrets.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: wordpress-secrets 5 | type: Opaque 6 | data: 7 | db-password: cGFzc3dvcmQ= 8 | -------------------------------------------------------------------------------- /wordpress/wordpress-service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: wordpress-service 5 | spec: 6 | ports: 7 | - port: 31001 8 | nodePort: 31001 9 | targetPort: http-port 10 | protocol: TCP 11 | selector: 12 | app: wordpress 13 | type: NodePort 14 | -------------------------------------------------------------------------------- /wordpress/wordpress-single-deployment-no-volumes.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: wordpress-deployment 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: wordpress 10 | template: 11 | metadata: 12 | labels: 13 | app: wordpress 14 | spec: 15 | containers: 16 | - name: wordpress 17 | image: wordpress:6-php8.0 18 | ports: 19 | - name: http-port 20 | containerPort: 80 21 | env: 22 | - name: WORDPRESS_DB_PASSWORD 23 | valueFrom: 24 | secretKeyRef: 25 | name: wordpress-secrets 26 | key: db-password 27 | - name: WORDPRESS_DB_HOST 28 | value: 127.0.0.1 29 | - name: WORDPRESS_DB_USER 30 | value: root 31 | - name: WORDPRESS_DB_NAME 32 | value: wordpress 33 | - name: mysql 34 | image: mysql:8 35 | ports: 36 | - name: mysql-port 37 | containerPort: 3306 38 | env: 39 | - name: MYSQL_DATABASE 40 | value: wordpress 41 | - name: MYSQL_ROOT_PASSWORD 42 | valueFrom: 43 | secretKeyRef: 44 | name: wordpress-secrets 45 | key: db-password 46 | --------------------------------------------------------------------------------