├── ping.yml ├── python.sh ├── AnsibleHosts ├── ansible.sh ├── ReadMe.md ├── .gitattributes ├── master.sh ├── .gitignore ├── Vagrantfile ├── docker-stack.yml └── DeployDocker.yml /ping.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: nodes 3 | tasks: 4 | - ping: 5 | 6 | -------------------------------------------------------------------------------- /python.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | apt-get update 4 | apt-get install -y python -------------------------------------------------------------------------------- /AnsibleHosts: -------------------------------------------------------------------------------- 1 | [master] 2 | 127.0.0.1 3 | [nodes] 4 | 192.168.33.11 5 | 192.168.33.12 6 | -------------------------------------------------------------------------------- /ansible.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | apt-get update 4 | apt-get install -y python ansible 5 | -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | **DevOps Home Lab** 2 | 3 | This repository contains a small collection of configuration files to create a very basic DevOps home lab for an IT infrastructure professional. 4 | 5 | It uses Vagrant to provision three Ubuntu VMs. Then uses Ansible to deploy Docker and create a swarm. 6 | 7 | This home lab was originally created for a TechTarget article, when the article is published I will ad a link from here. 8 | 9 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /master.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | sudo apt-get install sshpass 4 | ssh-keygen -b 2048 -t rsa -f /home/vagrant/.ssh/id_rsa -q -N "" 5 | sshpass -p vagrant ssh-copy-id -o StrictHostKeyChecking=no vagrant@192.168.33.11 6 | sshpass -p vagrant ssh-copy-id -o StrictHostKeyChecking=no vagrant@192.168.33.12 7 | sudo cp /vagrant/AnsibleHosts /etc/ansible/hosts 8 | ansible-playbook /vagrant/DeployDocker.yml 9 | sudo docker stack deploy --compose-file /vagrant/docker-stack.yml vote -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # All Vagrant configuration is done below. The "2" in Vagrant.configure 5 | # configures the configuration version (we support older styles for 6 | # backwards compatibility). Please don't change it unless you know what 7 | # you're doing. 8 | Vagrant.configure(2) do |config| 9 | config.vm.define "node1" do |node1| 10 | node1.vm.box = "bento/ubuntu-16.04" 11 | node1.vm.hostname = 'node1' 12 | node1.vm.network :private_network, ip: "192.168.33.11" 13 | node1.vm.provision :shell, path: "python.sh" 14 | node1.vm.provider "virtualbox" do |v| 15 | v.memory = 512 16 | v.cpus = 1 17 | end 18 | end 19 | config.vm.define "node2" do |node2| 20 | node2.vm.box = "bento/ubuntu-16.04" 21 | node2.vm.hostname = 'node2' 22 | node2.vm.network :private_network, ip: "192.168.33.12" 23 | node2.vm.provision :shell, path: "python.sh" 24 | node2.vm.provider "virtualbox" do |v| 25 | v.memory = 512 26 | v.cpus = 1 27 | end 28 | end 29 | config.vm.define "master", primary: true do |master| 30 | master.vm.hostname = 'master' 31 | master.vm.box = "bento/ubuntu-16.04" 32 | master.vm.network :private_network, ip: "192.168.33.10" 33 | master.vm.provision :shell, path: "ansible.sh" 34 | master.vm.provider "virtualbox" do |v| 35 | v.memory = 512 36 | v.cpus = 1 37 | end 38 | end 39 | 40 | end 41 | -------------------------------------------------------------------------------- /docker-stack.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | 4 | redis: 5 | image: redis:alpine 6 | ports: 7 | - "6379" 8 | networks: 9 | - frontend 10 | deploy: 11 | replicas: 2 12 | update_config: 13 | parallelism: 2 14 | delay: 10s 15 | restart_policy: 16 | condition: on-failure 17 | db: 18 | image: postgres:9.4 19 | volumes: 20 | - db-data:/var/lib/postgresql/data 21 | networks: 22 | - backend 23 | deploy: 24 | placement: 25 | constraints: [node.role == manager] 26 | vote: 27 | image: dockersamples/examplevotingapp_vote:before 28 | ports: 29 | - 5000:80 30 | networks: 31 | - frontend 32 | depends_on: 33 | - redis 34 | deploy: 35 | replicas: 2 36 | update_config: 37 | parallelism: 2 38 | restart_policy: 39 | condition: on-failure 40 | result: 41 | image: dockersamples/examplevotingapp_result:before 42 | ports: 43 | - 5001:80 44 | networks: 45 | - backend 46 | depends_on: 47 | - db 48 | deploy: 49 | replicas: 1 50 | update_config: 51 | parallelism: 2 52 | delay: 10s 53 | restart_policy: 54 | condition: on-failure 55 | 56 | worker: 57 | image: dockersamples/examplevotingapp_worker 58 | networks: 59 | - frontend 60 | - backend 61 | deploy: 62 | mode: replicated 63 | replicas: 1 64 | labels: [APP=VOTING] 65 | restart_policy: 66 | condition: on-failure 67 | delay: 10s 68 | max_attempts: 3 69 | window: 120s 70 | placement: 71 | constraints: [node.role == manager] 72 | 73 | visualizer: 74 | image: dockersamples/visualizer:stable 75 | ports: 76 | - "8080:8080" 77 | stop_grace_period: 1m30s 78 | volumes: 79 | - "/var/run/docker.sock:/var/run/docker.sock" 80 | deploy: 81 | placement: 82 | constraints: [node.role == manager] 83 | 84 | networks: 85 | frontend: 86 | backend: 87 | 88 | volumes: 89 | db-data: -------------------------------------------------------------------------------- /DeployDocker.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: 127.0.0.1 3 | connection: local 4 | become: true 5 | become_method: sudo 6 | tasks: 7 | - name: Create repository file for Docker 8 | file: path=/etc/apt/sources.list.d/docker.list state=touch 9 | - name: get APT keys 10 | apt_key: keyserver=hkp://p80.pool.sks-keyservers.net:80 id=58118E89F3A912897C070ADBF76221572C52609D 11 | - name: Add Docker repositories to APT 12 | lineinfile: dest=/etc/apt/sources.list.d/docker.list line='deb https://apt.dockerproject.org/repo ubuntu-xenial main' 13 | register: result 14 | - name: Apt upate for docker repositories 15 | apt: update_cache=yes 16 | when: result|changed 17 | - name: Install docker engine 18 | apt: name=docker-engine state=present install_recommends=yes 19 | - name: Start Docker service 20 | service: name=docker state=started 21 | - name: determine swarm status 22 | shell: "docker info | egrep '^Swarm: ' | cut -d ' ' -f2" 23 | register: swarm_status 24 | - name: initialize swarm cluster 25 | shell: docker swarm init --advertise-addr 192.168.33.10:2377 26 | when: "'active' not in swarm_status.stdout_lines" 27 | - name: retrieve swarm worker token 28 | shell: docker swarm join-token -q worker 29 | register: swarm_worker_token 30 | - name: Tag as docker manager 31 | shell: docker node update --role manager master 32 | when: "'active' not in swarm_status.stdout_lines" 33 | 34 | - hosts: nodes 35 | become: true 36 | become_method: sudo 37 | vars: 38 | token: "{{ hostvars['localhost']['swarm_worker_token']['stdout'] }}" 39 | tasks: 40 | - name: get APT keys 41 | apt_key: keyserver=hkp://p80.pool.sks-keyservers.net:80 id=58118E89F3A912897C070ADBF76221572C52609D 42 | - name: Create repository file for Docker 43 | file: path=/etc/apt/sources.list.d/docker.list state=touch 44 | - name: Add Docker repositories to APT 45 | lineinfile: dest=/etc/apt/sources.list.d/docker.list line='deb https://apt.dockerproject.org/repo ubuntu-xenial main' 46 | register: result 47 | - name: Apt upate for docker repositories 48 | apt: update_cache=yes 49 | when: result|changed 50 | - name: Install docker engine 51 | apt: name=docker-engine state=present install_recommends=yes 52 | - name: determine swarm status 53 | shell: "docker info | egrep '^Swarm: ' | cut -d ' ' -f2" 54 | register: swarm_status 55 | - name: join worker nodes to cluster 56 | shell: docker swarm join --token={{ token }} 192.168.33.10:2377 57 | when: "'active' not in swarm_status.stdout_lines" 58 | 59 | --------------------------------------------------------------------------------