├── .gitignore ├── vars ├── Darwin.yml └── RedHat.yml ├── templates └── kube.deployment.yml ├── kube-vars.yml ├── kube.deployment.playbook.yml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.retry 3 | 4 | -------------------------------------------------------------------------------- /vars/Darwin.yml: -------------------------------------------------------------------------------- 1 | manifest_base_dir: ~/kubernetes_manifests 2 | manifest_app_dir: "{{manifest_base_dir}}/{{app.name}}" 3 | deployment_file: "kube.deployment.yml" -------------------------------------------------------------------------------- /vars/RedHat.yml: -------------------------------------------------------------------------------- 1 | manifest_base_dir: /kubernetes_manifests 2 | manifest_app_dir: "{{manifest_base_dir}}/{{app.name}}" 3 | deployment_file: "kube.deployment.yml" -------------------------------------------------------------------------------- /templates/kube.deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{app.name}} 5 | labels: 6 | app: {{app.name}} 7 | spec: 8 | type: NodePort 9 | ports: 10 | - name: http-{{app.name}} 11 | protocol: TCP 12 | nodePort: {{app.nodePort}} 13 | port: {{app.port}} 14 | selector: 15 | app: {{app.name}} 16 | --- 17 | apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 18 | kind: Deployment 19 | metadata: 20 | name: {{app.name}} 21 | labels: 22 | app: {{app.name}} 23 | spec: 24 | selector: 25 | matchLabels: 26 | app: {{app.name}} 27 | strategy: 28 | type: Recreate 29 | template: 30 | metadata: 31 | labels: 32 | app: {{app.name}} 33 | spec: 34 | containers: 35 | - image: {{container_image}} 36 | name: {{app.name}} -------------------------------------------------------------------------------- /kube-vars.yml: -------------------------------------------------------------------------------- 1 | 2 | # If we should deploy this kubernetes or not. 3 | # Setting this to false and re-running our deploy playbook will remove the kubernetes deployment 4 | # example to remove: ansible-playbook kubernetes/kube.deployment.playbook.yml --extra-vars '{deployment_enabled: false}' 5 | deployment_enabled: true 6 | 7 | # Docker registry where this image will come from 8 | docker_registry: kiab.local:5000 9 | 10 | # Variabled specific to our app or service 11 | app: 12 | # Name our app or service 13 | name: 14 | # Name of our container image within our registry 15 | container_name: 16 | # Tag of our image within our registry 17 | container_tag: 18 | # Port exposed on kubernetes worker 19 | nodePort: 30180 20 | # Port exposed to the pod - note that nodePort is typically forwarded to this port 21 | port: 5000 22 | 23 | # A compiled variable of our image we will run in the pod 24 | # Note: this needs to be built outside of our our app: context due to a recursion bug in jinja2 25 | container_image: "{{docker_registry}}/{{app.container_name}}:{{app.container_tag}}" -------------------------------------------------------------------------------- /kube.deployment.playbook.yml: -------------------------------------------------------------------------------- 1 | - hosts: 2 | - localhost 3 | vars_files: 4 | - ./kube-vars.yml 5 | tasks: 6 | - include_vars: "vars/{{ ansible_os_family }}.yml" 7 | 8 | - fail: 9 | msg: "Please specify an app name and all relevant info in kube-vars.yml to use this" 10 | when: "app.name == ''" 11 | 12 | - name: ensure manifest dir exists 13 | file: 14 | path: "{{manifest_app_dir}}" 15 | state: directory 16 | 17 | - name: kubectl get secrets 18 | shell: kubectl get secrets 19 | register: kube_secrets 20 | 21 | - name: create manifest template for kube deploy 22 | template: 23 | src: "{{deployment_file}}" 24 | dest: "{{manifest_app_dir}}/{{deployment_file}}" 25 | register: deploy_template 26 | 27 | # Applys 28 | - block: 29 | - name: apply kubernetes deployment 30 | shell: "kubectl apply -f {{manifest_app_dir}}/{{deployment_file}}" 31 | when: "deployment_enabled" 32 | 33 | 34 | # Removals 35 | - block: 36 | - name: remove kubernetes deployment 37 | shell: "kubectl delete -f {{manifest_app_dir}}/{{deployment_file}}" 38 | register: remove_kube_deployment 39 | when: not deployment_enabled 40 | 41 | 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CICD Deploymet to Kubernetes using Ansible 2 | The purpose of this repository is to demonstrate how to deploy an app/service to Kubernetes using Ansible which can easily be run locally by a developer or a CI/CD platform such as Jenkins with little modification of the actual deployment code. This ensures that what we develop locally on mimics how we deploy and run on production. 3 | 4 | First and formost, this is meant to be boilerplate code; Just enough to get you started if you will. Its best if you cloned this into your existing app code repository with something like `git clone https://github.com/nickmaccarthy/ansible-kubernetes-deployment-sample.git _kubernetes && rm -rf _kubernetes/.git`. Please see the `Files` section below for documentation on what each file represents and does. 5 | 6 | Here we run an Ansible playbook which creates a template file on the host where `kubectl` runs from, which we then run a `kubectl apply` which is what actually deploys to Kubernetes. Since we are utilizing Ansible here we can utilize all that Ansible has to offer if we need to make deployments to Kubernetes more streamlined and efficient. 7 | 8 | By default, our `kube.deployment.yml` is a basic [NodePort](https://kubernetes.io/docs/concepts/services-networking/service/#nodeport) deployment in Kubernetes. This helps emulate how many developers might develop against a `docker-compose` or with just a `docker run`. This tempalte file can and should be modified to meet your needs for your specific app or service. Remember this is just sample code, meant to just you going. All modifications can then live your in app codes SCM going forward after you have cloned this in there. 9 | 10 | ## Files 11 | * `kube.deployment.playbook.yml` - The main deployment playbook used to deploy to kubernetes 12 | 13 | * `kube-vars.yml` - variables that determine our service specific items, like ports, container image, tag, etc within the kubernetes template or application/deployment. These can change and could even be made for different envrionments and each item within this could be overriden by passing along the `--extra-vars` flag when running `ansbile-playbook`. 14 | 15 | * `templates/kube_deployment.yml` - This is a base template used to create a basic kubernetes deployment and pod. This can easily be modified to meet your needs for your service 16 | 17 | ## Usage 18 | 1. Clone this repo into your application code repository 19 | * `git clone https://github.com/nickmaccarthy/ansible-kubernetes-deployment-sample.git _kubernetes && rm -rf _kubernetes/.git` 20 | 2. Modify the `kube-vars.yml` file to meet your needs 21 | 3. Deploy your your kubernetes cluster 22 | * `ansible-playbook _kubernetes/kube.deployment.playbook.yml` 23 | 24 | Note: If you wanted to backout the deployment running in Kubernetes, simply run this command: `ansible-playbook _kubernetes/kube.deployment.playbook.yml --extra-vars '{deployment_enabled: false}'` 25 | 26 | ## Protip's 27 | You can automate most of this with a Makefile. Check out this Repo for more information 28 | 29 | ## Examples 30 | Check out this repo for how this might look for an application code/deployment for more information. I built a sample python Flask application that uses this repo for deployment a local K8S cluster. Check out - [k8s-flask-app-sample](https://github.com/nickmaccarthy/k8s-flask-app-sample) --------------------------------------------------------------------------------