├── .github └── workflows │ └── pythonapp.yml ├── README.md ├── docs ├── Commands.md ├── Deploying_Applications_With_Flux.md ├── Flux_Install_Yaml.md ├── Sample_YAML.md ├── Using_Manifests_With_Flux_Lab.md └── Using_Pull_Requests_For_Release_Gating.md ├── namespaces └── lasample.yaml ├── production └── README.md ├── python ├── Dockerfile ├── app.py └── requirements.txt ├── qa └── README.md └── workloads └── nginx.yaml /.github/workflows/pythonapp.yml: -------------------------------------------------------------------------------- 1 | name: Python application 2 | 3 | on: 4 | push: 5 | paths: 6 | - 'python/*' 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v1 15 | - name: Set up Python 3.7 16 | uses: actions/setup-python@v1 17 | with: 18 | python-version: 3.7 19 | - name: Install dependencies 20 | run: | 21 | python -m pip install --upgrade pip 22 | pip install -r ./python/requirements.txt 23 | - name: Build & Push Image 24 | run: | 25 | cd ./python 26 | echo "${{ secrets.DOCKERPW }}" | docker login -u "[your dockerhub login here]" --password-stdin 27 | docker image build -t [your dockerhub username here]/gitops:hellov1.0 . 28 | docker push [your docker hub username here]/gitops:hellov1.0 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![la logo](https://user-images.githubusercontent.com/42839573/67322755-818e9400-f4df-11e9-97c1-388bf357353d.png) 2 | 3 | ### Linux Academy Course Repository 4 | ### Hands-On GitOps 5 | 6 | This repository is a resource provided for Linux Academy students taking the hands-on GitIOps course. 7 | -------------------------------------------------------------------------------- /docs/Commands.md: -------------------------------------------------------------------------------- 1 | ![la logo](https://user-images.githubusercontent.com/42839573/67322755-818e9400-f4df-11e9-97c1-388bf357353d.png) 2 | 3 | ## Hands-On GitOps 4 | 5 | ### This document contains a number of commands that may prove useful to the student. 6 | 7 | This is the command to install fluxctl on an Ubuntu server. 8 | > Note: After the publication of this course, the maintainers of snap added the confinement security feature. Depending on Weavework's maintenance of the fluxctl binaries in the snap repositories, it may be necessary to add the "--classic" flag to the flux install command. 9 | 10 | ``` 11 | $ sudo snap install fluxctl 12 | ``` 13 | or 14 | ``` 15 | $ sudo snap install --classic 16 | ``` 17 | To check that fluxctl is installed: 18 | 19 | ``` 20 | $ fluxctl version 21 | ``` 22 | > Note: At the time of the publication of this course, the binaries in the snap repo were an unversioned version. You may have a different response when you take the course. 23 | 24 | This is the command to check the kubernetes cluster that is staged. 25 | 26 | ``` 27 | $ kubctl get nodes 28 | ``` 29 | 30 | This is the command to create a namespace called flux. 31 | 32 | ``` 33 | $ kubectl create namespace flux 34 | ``` 35 | 36 | The following is the fluxctl install command used to deploy the flux pods to a cluster within the flux namespace. This is the example used in the "Installing with GitHub Lab". 37 | 38 | ``` 39 | $ fluxctl install \ 40 | --git-user=${GHUSER} \ 41 | --git-email=${GHUSER}@users.noreply.github.com \ 42 | --git-url=git@github.com:${GHUSER}/content-gitops \ 43 | --git-path=namespaces,workloads \ 44 | --namespace=flux | kubectl apply -f - 45 | ``` 46 | The version of this command used in the "Installing with GitLab Lab" is: 47 | 48 | ``` 49 | $ export GLUSER=[your GitLab username] 50 | ``` 51 | Then input the command to run flux: 52 | ``` 53 | $ fluxctl install \ 54 | --git-user=${GLUSER} \ 55 | --git-email=${GLUSER}@gmail.com \ 56 | --git-url=git@gitlab.com:${GLUSER}/flux-sample \ 57 | --git-path=namespaces,workloads \ 58 | --namespace=flux | kubectl apply -f - 59 | ``` 60 | > Note: In the above sample 'flux-sample' is an example repo name. You would use the actual url for the repo you wish Flux to scan. 61 | 62 | This is the command to check the status of the flux deployment. 63 | 64 | ``` 65 | $ kubectl -n flux rollout status deployment/flux 66 | ``` 67 | 68 | This is the command to interogate the RSA Key created by the flux install. 69 | 70 | ``` 71 | $ fluxctl identity --k8s-fwd-ns flux 72 | ``` 73 | 74 | This is the command to cause flux to sync with the repo. 75 | 76 | ``` 77 | $ fluxctl sync --k8s-fwd-ns flux 78 | ``` 79 | 80 | This is the command to set an environment variable to tell fluxctl the namespace that flux is running in. 81 | 82 | ``` 83 | $ export FLUX_FORWARD_NAMESPACE=flux 84 | ``` 85 | 86 | This is the command to list flux workloads 87 | 88 | ``` 89 | $ fluxctl list-workloads 90 | ``` 91 | and... 92 | ``` 93 | $ fluxctl list-workloads --all-namespaces 94 | ``` 95 | and... 96 | ``` 97 | $ fluxctl -n lasample list-workloads 98 | ``` 99 | 100 | This is the command to list images running as flux workloads 101 | ``` 102 | $ fluxctl list-images 103 | ``` 104 | and... (specify namespace and deployment name, such as lasample and hello) 105 | ``` 106 | $ fluxctl list-images --workload lasample:deployment/hello 107 | ``` 108 | 109 | This is the command to get pods. 110 | ``` 111 | $ kubectl -n lasample get pods 112 | ``` 113 | 114 | This is the command to describe a specific pod such as hello-75d7f49d9b-t8bpr 115 | ``` 116 | $ kubectl -n lasample describe pod/hello-75d7f49d9b-t8bpr 117 | ``` 118 | 119 | The command to use fluxctl to add automation to an existing YAML file is: 120 | ``` 121 | $ fluxctl automate --workload=lamanifest:deployment/hello 122 | ``` 123 | 124 | The command to use fluxctl to reference a particular image stored in Docker Hub is: 125 | ``` 126 | $ fluxctl release --workload=lamanifest:deployment/hello --update-image=linuxacademycontent/gitops:hellov1.2 127 | ``` 128 | 129 | The command to remove automation from an existing deployment YAML is: 130 | ``` 131 | $ fluxctl deautomate --workload=lasample:deployment/hello 132 | ``` 133 | 134 | To delete a namespace and all running pods within it: 135 | 136 | ``` 137 | $ kubectl delete namespace [namespace] 138 | ``` 139 | Note: This can be used to remove the flux deployment in your lab Kubernetes cluster. 140 | 141 | ### Git Commands 142 | 143 | The following command is used to set the username foe the git cli to access GitHub. 144 | 145 | ``` 146 | $ git config --global user.name "Your Username" 147 | ``` 148 | 149 | The following command will set the e-mail address required. 150 | 151 | ``` 152 | $ git config --global user.email "Your Username@users.noreply.github.com" 153 | ``` 154 | 155 | -------------------------------------------------------------------------------- /docs/Deploying_Applications_With_Flux.md: -------------------------------------------------------------------------------- 1 | ![la logo](https://user-images.githubusercontent.com/42839573/67322755-818e9400-f4df-11e9-97c1-388bf357353d.png) 2 | 3 | ### Deploying Applications With GitHub Actions Workflow and Flux 4 | 5 | ### Lab Scenario 6 | 7 | Your manager is impressed with Flux and wants to expand the proof-of-concept work you are doing beyond using Flux on a Development Server. He has asked you to setup a demo for some of the Operations and Engineering team to show how Flux can be used to promote workloads from Development, to Test and Production environments. 8 | 9 | #### For your use: 10 | 11 | The course repository linuxacademy/content-gitops has a sample yaml files. 12 | There are also documents in the docs directory with YAML, and a Commands file. 13 | 14 | #### Hint: 15 | If you have a repository from a prior lab in this course, then you can use it. Otherwise you may want to fork the linuxacademy/content-gitops repo. 16 | 17 | There are many ways to complete this task, but it is suggested that you use folders in the repository for QA and Production, to house the YAML for these upper environments. Then it is possible to configure Flux on the target environments to synchronize just the relevant YAML for that environment. 18 | 19 | The Docker hub repository with container images already built is at this Link: 20 | 21 | https://hub.docker.com/repository/docker/linuxacademycontent/gitops 22 | 23 | Good Luck! 24 | -------------------------------------------------------------------------------- /docs/Flux_Install_Yaml.md: -------------------------------------------------------------------------------- 1 | ### Flux Install YAML 2 | #### This is the output from fluxctl when we install the fluxd daemon. This is piped to kubectl so that it may be applied to the cluster. 3 | ``` 4 | --- 5 | apiVersion: v1 6 | kind: Secret 7 | metadata: 8 | name: flux-git-deploy 9 | namespace: flux 10 | type: Opaque 11 | --- 12 | # memcached deployment used by Flux to cache 13 | # container image metadata. 14 | apiVersion: apps/v1 15 | kind: Deployment 16 | metadata: 17 | name: memcached 18 | namespace: flux 19 | spec: 20 | replicas: 1 21 | selector: 22 | matchLabels: 23 | name: memcached 24 | template: 25 | metadata: 26 | labels: 27 | name: memcached 28 | spec: 29 | containers: 30 | - name: memcached 31 | image: memcached:1.5.15 32 | imagePullPolicy: IfNotPresent 33 | args: 34 | - -m 512 # Maximum memory to use, in megabytes 35 | - -I 5m # Maximum size for one item 36 | - -p 11211 # Default port 37 | # - -vv # Uncomment to get logs of each request and response. 38 | ports: 39 | - name: clients 40 | containerPort: 11211 41 | securityContext: 42 | runAsUser: 11211 43 | runAsGroup: 11211 44 | allowPrivilegeEscalation: false 45 | --- 46 | apiVersion: v1 47 | kind: Service 48 | metadata: 49 | name: memcached 50 | namespace: flux 51 | spec: 52 | ports: 53 | - name: memcached 54 | port: 11211 55 | selector: 56 | name: memcached 57 | --- 58 | # The service account, cluster roles, and cluster role binding are 59 | # only needed for Kubernetes with role-based access control (RBAC). 60 | apiVersion: v1 61 | kind: ServiceAccount 62 | metadata: 63 | labels: 64 | name: flux 65 | name: flux 66 | namespace: flux 67 | --- 68 | apiVersion: rbac.authorization.k8s.io/v1beta1 69 | kind: ClusterRole 70 | metadata: 71 | labels: 72 | name: flux 73 | name: flux 74 | rules: 75 | - apiGroups: ['*'] 76 | resources: ['*'] 77 | verbs: ['*'] 78 | - nonResourceURLs: ['*'] 79 | verbs: ['*'] 80 | --- 81 | apiVersion: rbac.authorization.k8s.io/v1beta1 82 | kind: ClusterRoleBinding 83 | metadata: 84 | labels: 85 | name: flux 86 | name: flux 87 | roleRef: 88 | apiGroup: rbac.authorization.k8s.io 89 | kind: ClusterRole 90 | name: flux 91 | subjects: 92 | - kind: ServiceAccount 93 | name: flux 94 | namespace: flux 95 | --- 96 | apiVersion: apps/v1 97 | kind: Deployment 98 | metadata: 99 | name: flux 100 | namespace: flux 101 | spec: 102 | replicas: 1 103 | selector: 104 | matchLabels: 105 | name: flux 106 | strategy: 107 | type: Recreate 108 | template: 109 | metadata: 110 | annotations: 111 | prometheus.io/port: "3031" # tell prometheus to scrape /metrics endpoint's port. 112 | labels: 113 | name: flux 114 | spec: 115 | serviceAccountName: flux 116 | volumes: 117 | - name: git-key 118 | secret: 119 | secretName: flux-git-deploy 120 | defaultMode: 0400 # when mounted read-only, we won't be able to chmod 121 | 122 | # This is a tmpfs used for generating SSH keys. In K8s >= 1.10, 123 | # mounted secrets are read-only, so we need a separate volume we 124 | # can write to. 125 | - name: git-keygen 126 | emptyDir: 127 | medium: Memory 128 | 129 | # The following volume is for using a customised known_hosts 130 | # file, which you will need to do if you host your own git 131 | # repo rather than using github or the like. You'll also need to 132 | # mount it into the container, below. See 133 | # https://docs.fluxcd.io/en/latest/guides/use-private-git-host.html 134 | # - name: ssh-config 135 | # configMap: 136 | # name: flux-ssh-config 137 | 138 | # The following volume is for using a customised .kube/config, 139 | # which you will need to do if you wish to have a different 140 | # default namespace. You will also need to provide the configmap 141 | # with an entry for `config`, and uncomment the volumeMount and 142 | # env entries below. 143 | # - name: kubeconfig 144 | # configMap: 145 | # name: flux-kubeconfig 146 | 147 | # The following volume is used to import GPG keys (for signing 148 | # and verification purposes). You will also need to provide the 149 | # secret with the keys, and uncomment the volumeMount and args 150 | # below. 151 | # - name: gpg-keys 152 | # secret: 153 | # secretName: flux-gpg-keys 154 | # defaultMode: 0400 155 | 156 | containers: 157 | - name: flux 158 | # There are no ":latest" images for flux. Find the most recent 159 | # release or image version at https://hub.docker.com/r/fluxcd/flux/tags 160 | # and replace the tag here. 161 | image: docker.io/fluxcd/flux:1.16.0 162 | imagePullPolicy: IfNotPresent 163 | resources: 164 | requests: 165 | cpu: 50m 166 | memory: 64Mi 167 | ports: 168 | - containerPort: 3030 # informational 169 | livenessProbe: 170 | httpGet: 171 | port: 3030 172 | path: /api/flux/v6/identity.pub 173 | initialDelaySeconds: 5 174 | timeoutSeconds: 5 175 | readinessProbe: 176 | httpGet: 177 | port: 3030 178 | path: /api/flux/v6/identity.pub 179 | initialDelaySeconds: 5 180 | timeoutSeconds: 5 181 | volumeMounts: 182 | - name: git-key 183 | mountPath: /etc/fluxd/ssh # to match location given in image's /etc/ssh/config 184 | readOnly: true # this will be the case perforce in K8s >=1.10 185 | - name: git-keygen 186 | mountPath: /var/fluxd/keygen # to match location given in image's /etc/ssh/config 187 | 188 | # Include this if you need to mount a customised known_hosts 189 | # file; you'll also need the volume declared above. 190 | # - name: ssh-config 191 | # mountPath: /root/.ssh 192 | 193 | # Include this and the volume "kubeconfig" above, and the 194 | # environment entry "KUBECONFIG" below, to override the config 195 | # used by kubectl. 196 | # - name: kubeconfig 197 | # mountPath: /etc/fluxd/kube 198 | 199 | # Include this to point kubectl at a different config; you 200 | # will need to do this if you have mounted an alternate config 201 | # from a configmap, as in commented blocks above. 202 | # env: 203 | # - name: KUBECONFIG 204 | # value: /etc/fluxd/kube/config 205 | 206 | # Include this and the volume "gpg-keys" above, and the 207 | # args below. 208 | # - name: gpg-keys 209 | # mountPath: /root/gpg-import 210 | # readOnly: true 211 | 212 | # Include this if you want to supply HTTP basic auth credentials for git 213 | # via the `GIT_AUTHUSER` and `GIT_AUTHKEY` environment variables using a 214 | # secret. 215 | # envFrom: 216 | # - secretRef: 217 | # name: flux-git-auth 218 | 219 | args: 220 | 221 | # If you deployed memcached in a different namespace to flux, 222 | # or with a different service name, you can supply these 223 | # following two arguments to tell fluxd how to connect to it. 224 | # - --memcached-hostname=memcached.default.svc.cluster.local 225 | 226 | # Use the memcached ClusterIP service name by setting the 227 | # memcached-service to string empty 228 | - --memcached-service= 229 | 230 | # This must be supplied, and be in the tmpfs (emptyDir) 231 | # mounted above, for K8s >= 1.10 232 | - --ssh-keygen-dir=/var/fluxd/keygen 233 | 234 | # Replace the following URL to change the Git repository used by Flux. 235 | # HTTP basic auth credentials can be supplied using environment variables: 236 | # https://$(GIT_AUTHUSER):$(GIT_AUTHKEY)@github.com/user/repository.git 237 | - --git-url=git@github.com:/content-gitops 238 | - --git-branch=master 239 | - --git-path=namespaces,production 240 | - --git-label=flux 241 | - --git-email=@users.noreply.github.com 242 | 243 | # Include these two to enable git commit signing 244 | # - --git-gpg-key-import=/root/gpg-import 245 | # - --git-signing-key= 246 | 247 | # Include this to enable git signature verification 248 | # - --git-verify-signatures 249 | 250 | # Tell flux it has readonly access to the repo (default `false`) 251 | # - --git-readonly 252 | 253 | # Instruct flux where to put sync bookkeeping (default "git", meaning use a tag in the upstream git repo) 254 | # - --sync-state=git 255 | 256 | # Include these next two to connect to an "upstream" service 257 | # (e.g., Weave Cloud). The token is particular to the service. 258 | # - --connect=wss://cloud.weave.works/api/flux 259 | # - --token=abc123abc123abc123abc123 260 | 261 | # Enable manifest generation (default `false`) 262 | # - --manifest-generation=false 263 | 264 | # Serve /metrics endpoint at different port; 265 | # make sure to set prometheus' annotation to scrape the port value. 266 | - --listen-metrics=:3031 267 | 268 | # Optional DNS settings, configuring the ndots option may resolve 269 | # nslookup issues on some Kubernetes setups. 270 | # dnsPolicy: "None" 271 | # dnsConfig: 272 | # options: 273 | # - name: ndots 274 | # value: "1" 275 | ``` 276 | -------------------------------------------------------------------------------- /docs/Sample_YAML.md: -------------------------------------------------------------------------------- 1 | ![la logo](https://user-images.githubusercontent.com/42839573/67322755-818e9400-f4df-11e9-97c1-388bf357353d.png) 2 | 3 | ### This file contains other YAML that helps the student with the lessons and labs in Linux Academy's Hands-On GitOps Course 4 | 5 | The following YAML file is used to create a namespace in the Kubernetes Cluster. 6 | 7 | ``` 8 | apiVersion: v1 9 | kind: Namespace 10 | metadata: 11 | labels: 12 | name: lasample 13 | name: lasample 14 | ``` 15 | 16 | The following is a YAML file to create a deployment of the sample Python Application. 17 | 18 | ``` 19 | apiVersion: apps/v1 20 | kind: Deployment 21 | metadata: 22 | name: hello 23 | namespace: lasample 24 | labels: 25 | app: hello 26 | spec: 27 | selector: 28 | matchLabels: 29 | app: hello 30 | template: 31 | metadata: 32 | labels: 33 | app: hello 34 | spec: 35 | containers: 36 | - name: hello 37 | image: linuxacademycontent/gitops:hellov1.0 38 | ``` 39 | 40 | The following is a sample YAML file to create a Service for the hello application. 41 | 42 | ``` 43 | kind: Service 44 | apiVersion: v1 45 | metadata: 46 | name: hello-service 47 | namespace: lasample 48 | spec: 49 | selector: 50 | app: hello 51 | ports: 52 | - protocol: TCP 53 | port: 8000 54 | nodePort: 32321 55 | type: NodePort 56 | ``` 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/Using_Manifests_With_Flux_Lab.md: -------------------------------------------------------------------------------- 1 | ![la logo](https://user-images.githubusercontent.com/42839573/67322755-818e9400-f4df-11e9-97c1-388bf357353d.png) 2 | 3 | ### Using Manifests With Flux 4 | 5 | ### Lab Scenario 6 | 7 | Your manager is interested in using Flux to synchronize a Kubernetes Cluster with Kubernetes Manifests stored in a GitHub Repo. The Development Organization has pushed several releases of an application called 'Hello' to docker hub. The team would like you to set up a repository with the YAML required to create a namespace and deploy the container image on docker hub. 8 | 9 | #### For your use: 10 | 11 | Sample commands may be found in the Commands.md file within this repo. 12 | Sample YAML may be found in the Sample_YAML.md file within this repo. 13 | 14 | #### Hint: 15 | The YAML provided references a namespace and a container image. They may not be 'ready for production' based on the images that have been pushed and tagged in Docker Hub. 16 | 17 | You will want to use the fluxctl automate and release commands to make the YAML work, and you will also need to be sure the namespace that you create is the same as the namespace referenced in the workloads deployment YAML. 18 | 19 | The Docker hub Link is: 20 | https://hub.docker.com/repository/docker/linuxacademycontent/gitops 21 | 22 | Good Luck! 23 | -------------------------------------------------------------------------------- /docs/Using_Pull_Requests_For_Release_Gating.md: -------------------------------------------------------------------------------- 1 | ![la logo](https://user-images.githubusercontent.com/42839573/67322755-818e9400-f4df-11e9-97c1-388bf357353d.png) 2 | 3 | ### Using Pull Requests For Release Gating 4 | 5 | ### Lab Scenario 6 | 7 | Your manager is interested in using Flux to synchronize a Kubernetes Cluster with Kubernetes Manifests stored in a GitHub Repo. The Development Organization needs to push releases of their application up to Docker Hub so they can be deployed by Flux. The team would like you to set up a repository with the YAML required to use GitHub Actions Workflow to build the container, tag it, and push it to Docker Hub. 8 | 9 | #### For your use: 10 | 11 | The course repository linuxacademy/content-gitops has a sample workflow file as well as a Python application called hello in the python directory. 12 | 13 | #### Hint: 14 | You will need to fork the Linux Academy repo to your own GitHub Account. You will also need an account on Docker Hub to push container images to. 15 | 16 | The Docker hub Link is: 17 | https://hub.docker.com/repository/docker/linuxacademycontent/gitops 18 | 19 | Good Luck! 20 | 21 | ### SPECIAL INSTRUCTIONS 22 | 23 | For the workflow that has been setup to work properly, you will need to substitute your username into the workflow where the docker login command is done. You will also need to add a secret to your github repo for the Docker Hub password. It is suggested you add your dockerhub password as a secret named DOCKERPW in your github repo. 24 | 25 | 26 | -------------------------------------------------------------------------------- /namespaces/lasample.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | labels: 5 | name: lasample 6 | name: lasample 7 | -------------------------------------------------------------------------------- /production/README.md: -------------------------------------------------------------------------------- 1 | This folder is for YAML to deploy workloads into production. 2 | -------------------------------------------------------------------------------- /python/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3-alpine 2 | COPY . /python 3 | WORKDIR /python 4 | RUN pip install -r requirements.txt 5 | CMD python /python/app.py 6 | -------------------------------------------------------------------------------- /python/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | app = Flask(__name__) 3 | 4 | @app.route("/") 5 | def hello(): 6 | return "Hello World!" 7 | 8 | if __name__ == "__main__": 9 | app.run(host='0.0.0.0', port=8000) 10 | -------------------------------------------------------------------------------- /python/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==1.0.2 2 | -------------------------------------------------------------------------------- /qa/README.md: -------------------------------------------------------------------------------- 1 | This folder is for the yaml to deploy into QA Test Environments. 2 | -------------------------------------------------------------------------------- /workloads/nginx.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: nginx-deployment 5 | namespace: lasample 6 | labels: 7 | app: nginx 8 | spec: 9 | replicas: 2 10 | selector: 11 | matchLabels: 12 | app: nginx 13 | template: 14 | metadata: 15 | labels: 16 | app: nginx 17 | spec: 18 | containers: 19 | - name: nginx 20 | image: nginx:1.7.9 21 | ports: 22 | - containerPort: 80 23 | --------------------------------------------------------------------------------