├── ansible ├── master │ ├── ansible │ │ ├── ping_all.yml │ │ ├── install_php.yml │ │ └── inventory │ └── Dockerfile ├── host │ ├── run.sh │ └── Dockerfile ├── base │ └── Dockerfile └── docker-compose.yml ├── LICENSE └── README.md /ansible/master/ansible/ping_all.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | tasks: 4 | - ping: 5 | -------------------------------------------------------------------------------- /ansible/master/ansible/install_php.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: web 3 | tasks: 4 | - name: Install PHP 5 | apt: name=php-cli state=present update_cache=yes 6 | become: true 7 | -------------------------------------------------------------------------------- /ansible/master/ansible/inventory: -------------------------------------------------------------------------------- 1 | [web] 2 | host0[1:2] ansible_user=root ansible_ssh_private_key_file=/var/ans/master_key 3 | [db] 4 | host03 ansible_user=root ansible_ssh_private_key_file=/var/ans/master_key 5 | -------------------------------------------------------------------------------- /ansible/host/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # add a master public key to authorized_keys on host in order to allow SSH connections 4 | cat /var/ans/master_key.pub >> /root/.ssh/authorized_keys 5 | 6 | # start SSH server 7 | /usr/sbin/sshd -D 8 | -------------------------------------------------------------------------------- /ansible/host/Dockerfile: -------------------------------------------------------------------------------- 1 | # HOST image - used to create containers to be managed by master 2 | 3 | # use builded ansible_base (defined in ../base/Dockerfile) as a starting point 4 | FROM ansible_base:latest 5 | 6 | # copy script from local disk to file system inside Docker image 7 | COPY run.sh /var/ 8 | 9 | # adjust file permissions to make run.sh executable 10 | RUN chmod 755 /var/run.sh 11 | -------------------------------------------------------------------------------- /ansible/base/Dockerfile: -------------------------------------------------------------------------------- 1 | # BASE image - used as a starting point by MASTER and HOST images 2 | 3 | # I use official Ubuntu 17.10 image as a starting point 4 | FROM ubuntu:17.10 5 | 6 | # install required packages 7 | RUN apt-get update \ 8 | && apt-get install --no-install-recommends --no-install-suggests -y \ 9 | aptitude iputils-ping net-tools man vim openssh-server python \ 10 | && rm -rf /var/lib/apt/lists/* 11 | 12 | # ensure that required directories are created 13 | RUN mkdir /var/run/sshd 14 | RUN mkdir /root/.ssh 15 | -------------------------------------------------------------------------------- /ansible/master/Dockerfile: -------------------------------------------------------------------------------- 1 | # MASTER image - used to create the master container to manage hosts 2 | 3 | # use builded ansible_base (defined in ../base/Dockerfile) as a starting point 4 | FROM ansible_base:latest 5 | 6 | # install ansible package 7 | RUN apt-get update \ 8 | && apt-get install --no-install-recommends --no-install-suggests -y \ 9 | ansible 10 | 11 | # copy content of ansible directory from local disk to file system inside Docker image 12 | COPY ansible /var/ans/ 13 | 14 | # change working directory 15 | WORKDIR /var/ans 16 | 17 | # generate RSA key pair to allow master to communicate with managed nodes 18 | # default private key passphrase is '12345' (not a good idea for production environment ;) 19 | RUN ssh-keygen -t rsa -N 12345 -C "master key" -f master_key 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 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 | -------------------------------------------------------------------------------- /ansible/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | base: 4 | build: ./base/ 5 | image: ansible_base 6 | master: 7 | links: 8 | - base 9 | build: ./master/ 10 | image: ansible_master 11 | container_name: master01 12 | hostname: master01 13 | command: ["/usr/sbin/sshd","-D"] 14 | volumes: 15 | - ansible_vol:/var/ans 16 | host: 17 | links: 18 | - base 19 | - master 20 | build: ./host/ 21 | image: ansible_host 22 | container_name: host01 23 | hostname: host01 24 | command: ["/var/run.sh"] 25 | volumes: 26 | - ansible_vol:/var/ans 27 | host02: 28 | links: 29 | - base 30 | - master 31 | - host 32 | image: ansible_host 33 | container_name: host02 34 | hostname: host02 35 | command: ["/var/run.sh"] 36 | volumes: 37 | - ansible_vol:/var/ans 38 | host03: 39 | links: 40 | - base 41 | - master 42 | - host 43 | image: ansible_host 44 | container_name: host03 45 | hostname: host03 46 | command: ["/var/run.sh"] 47 | volumes: 48 | - ansible_vol:/var/ans 49 | volumes: 50 | ansible_vol: -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | The aim of this guide is setup of [Ansible](https://www.ansible.com/) training environment using [Docker](https://www.docker.com/) containers. After finishing this tutorial you will have Docker master container that can manage three host containers (you can easily extend number of managed hosts to meet your needs). 4 | 5 | Why I decided to use Docker instead of conventional virtualization like [VirtualBox](https://www.virtualbox.org/)? Docker containers consume much less resources so you can build bigger test environments on your laptop. Docker container is way faster to start/kill than standard virtual machine which is important when you experiment and bring the whole environment up and down. I used [Docker Compose](https://docs.docker.com/compose/overview/) to automate setup of lab environment (there is no need to maintain each container separately). 6 | 7 | This guide **is not** Ansible or Docker tutorial (although I explain some basic concepts). It's purpose is solely setup of lab environment to enable experiments with ansible on local machine. 8 | 9 | **IMPORTANT**: In order to follow this tutorial you need to install Docker CE (Community Edition) on your machine. The installation is well documented at https://docs.docker.com/engine/installation/#supported-platforms and I will not cover it here. 10 | 11 | A brief description of Ansible and Docker: 12 | 13 | ## Ansible 14 | 15 | Ansible is IT automation system. It handles configuration-management, application deployment, cloud provisioning, ad-hoc task-execution, and multinode orchestration - including trivializing things like zero downtime rolling updates with load balancers. 16 | 17 | You can read more at [www.ansible.com](https://www.ansible.com/) 18 | 19 | ## Docker 20 | 21 | Docker is the world’s leading software container platform. Developers use Docker to eliminate "works on my machine" problems when collaborating on code with co-workers. Operators use Docker to run and manage apps side-by-side in isolated containers to get better compute density. Enterprises use Docker to build agile software delivery pipelines to ship new features faster, more securely and with confidence for both Linux, Windows Server, and Linux-on-mainframe apps. 22 | 23 | You can read more at [www.docker.com](https://www.docker.com/) 24 | 25 | # Quick start 26 | 27 | ## Clone repository 28 | 29 | Clone this git repository: 30 | 31 | `git clone https://github.com/LMtx/ansible-lab-docker.git` 32 | 33 | ## Build images and run containers 34 | 35 | Enter **ansible** directory containing [docker-compose.yml](./ansible/docker-compose.yml) file. 36 | 37 | Build docker images and run containers in the background (details defined in [docker-compose.yml](./ansible/docker-compose.yml)): 38 | 39 | `docker-compose up -d --build` 40 | 41 | Connect to **master node**: 42 | 43 | `docker exec -it master01 bash` 44 | 45 | Verify if network connection is working between master and managed hosts: 46 | 47 | `ping -c 2 host01` 48 | 49 | Start an [SSH Agent](https://man.openbsd.org/ssh-agent) on **master node** to handle SSH keys protected by passphrase: 50 | 51 | `ssh-agent bash` 52 | 53 | Load private key into SSH Agent in order to allow establishing connections without entering key passphrase every time: 54 | 55 | `ssh-add master_key` 56 | 57 | Enter passphrase for master_key: 58 | 59 | As **passphrase** enter: `12345` 60 | 61 | Default key passphrase can be changed in [ansible/master/Dockerfile](./ansible/master/Dockerfile) 62 | 63 | ## Ansible playbooks 64 | 65 | Run a [sample ansible playbook](./ansible/master/ansible/ping_all.yml) that checks connection between master node and managed hosts: 66 | 67 | `ansible-playbook -i inventory ping_all.yml` 68 | 69 | Confirm _every_ new host for SSH connections: 70 | 71 | ECDSA key fingerprint is SHA256:HwEUUnBtOm9hVAR2PJflNdCVchSCzIlpOpqYlwp+w+w. 72 | Are you sure you want to continue connecting (yes/no)? 73 | 74 | Type: `yes` (three times) 75 | 76 | Install PHP on web **inventory group**: 77 | 78 | In order to group managed hosts for easier maintenance you can use groups in ansible [inventory file](./ansible/master/ansible/inventory). 79 | 80 | Run a [sample ansible playbook](./ansible/master/ansible/install_php.yml): 81 | 82 | `ansible-playbook -i inventory install_php.yml` 83 | 84 | ## Copy data between local file system and containers 85 | 86 | ### Copy directory from container to local file system 87 | 88 | `docker cp master01:/var/ans/ .` 89 | 90 | ### Copy directory from local file system to container: 91 | 92 | `docker cp ./ans master01:/var/` 93 | 94 | You can check usage executing: 95 | 96 | `docker cp --help` 97 | 98 | ## Cleanup 99 | 100 | After you are done with your experiments or want to destroy lab environment to bring new one execute following commands. 101 | 102 | Stop containers: 103 | 104 | `docker-compose kill` 105 | 106 | Remove containers: 107 | 108 | `docker-compose rm` 109 | 110 | 111 | Remove volume: 112 | 113 | `docker volume rm ansible_ansible_vol` 114 | 115 | If you want you can remove Docker images (although that is not required to start new lab environment): 116 | 117 | `docker rmi ansible_host ansible_master ansible_base` 118 | 119 | # Tips 120 | 121 | In order to share public SSH key between **master** and **host** containers I used Docker **volume** mounted to all containers: 122 | 123 | [docker-compose.yml](./ansible/docker-compose.yml): 124 | 125 | [...] 126 | volumes: 127 | - ansible_vol:/var/ans 128 | [...] 129 | 130 | Master container stores SSH key in that volume ([ansible/master/Dockerfile](./ansible/master/Dockerfile)): 131 | 132 | [...] 133 | WORKDIR /var/ans 134 | RUN ssh-keygen -t rsa -N 12345 -C "master key" -f master_key 135 | [...] 136 | 137 | And host containers add SSH public key to authorized_keys file ([ansible/host/run.sh](./ansible/host/run.sh)) in order to allow connections from master: 138 | 139 | cat /var/ans/master_key.pub >> /root/.ssh/authorized_keys 140 | 141 | **IMPORTANT:** this is valid setup for lab environment but for production deployment you have to distribute the public key other way. 142 | 143 | # Troubleshooting 144 | 145 | ## Host containers stop after creation 146 | 147 | Check that [ansible/hosts/run.sh](./ansible/host/run.sh) has proper end of line type - it **should be Linux/Unix (LF)** not Windows (CRLF). You can change end of line type using source code editor (like Notepad++ or Visual Studio Code); under Linux you can use `dos2unix` command. 148 | 149 | ## Other issue 150 | 151 | Please open an [issue](https://github.com/LMtx/ansible-lab-docker/issues/new) and I'll try to help. 152 | --------------------------------------------------------------------------------