├── README.md ├── Vagrantfile ├── hosts └── solution ├── 1.LabSetup └── README.md ├── 2.Ansible ├── README.md ├── myhosts └── playbook1.yml ├── 3.Docker ├── Dockerfile ├── README.md ├── app.py ├── docker-compose.yml └── requirements.txt ├── 4.DockerSwarm ├── README.md └── myapp │ ├── Dockerfile │ ├── app.py │ ├── docker-compose.yml │ └── requirements.txt ├── Vagrantfile └── hosts /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # YouTube Tutorial Below 4 | https://www.youtube.com/watch?v=YuZ002YrvUA 5 | 6 | # Vagrant Cheatsheet 7 | https://gist.github.com/wpscholar/a49594e2e2b918f4d0c4 8 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | Vagrant.configure("2") do |config| 2 | servers=[ 3 | { 4 | :hostname => "control", 5 | :box => "bento/ubuntu-18.04", 6 | :ip => "172.16.1.50", 7 | :ssh_port => '2200' 8 | }, 9 | { 10 | :hostname => "node1", 11 | :box => "bento/ubuntu-18.04", 12 | :ip => "172.16.1.51", 13 | :ssh_port => '2201' 14 | }, 15 | { 16 | :hostname => "node2", 17 | :box => "bento/ubuntu-18.04", 18 | :ip => "172.16.1.52", 19 | :ssh_port => '2202' 20 | } 21 | ] 22 | 23 | servers.each do |machine| 24 | config.vm.define machine[:hostname] do |node| 25 | node.vm.box = machine[:box] 26 | node.vm.hostname = machine[:hostname] 27 | node.vm.network :private_network, ip: machine[:ip] 28 | node.vm.network "forwarded_port", guest: 22, host: machine[:ssh_port], id: "ssh" 29 | node.vm.provider :virtualbox do |vb| 30 | vb.customize ["modifyvm", :id, "--memory", 512] 31 | vb.customize ["modifyvm", :id, "--cpus", 1] 32 | end 33 | end 34 | end 35 | end -------------------------------------------------------------------------------- /hosts: -------------------------------------------------------------------------------- 1 | 127.0.0.1 localhost 2 | 127.0.1.1 vagrant.vm vagrant 3 | 4 | # The following lines are desirable for IPv6 capable hosts 5 | ::1 localhost ip6-localhost ip6-loopback 6 | ff02::1 ip6-allnodes 7 | ff02::2 ip6-allrouters 8 | 9 | 172.16.1.50 control 10 | 172.16.1.51 node1 11 | 172.16.1.52 node2 12 | 172.16.1.53 node3 -------------------------------------------------------------------------------- /solution/1.LabSetup/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Install Vagrant 3 | https://www.vagrantup.com/docs/installation 4 | 5 | 6 | # Install Oracle Virtualbox 7 | 8 | https://www.vagrantup.com/docs/providers/virtualbox 9 | 10 | 11 | 12 | # Lab 13 | ``` 14 | vagrant up 15 | vagrant ssh control 16 | ``` 17 | 18 | ### Copy over hosts file 19 | 20 | ``` 21 | sudo cp /vagrant/hosts /etc/hosts 22 | ``` 23 | 24 | 25 | https://gist.github.com/devopsjourney1/7a5f21fddef564eb8c68dd7901d0f6be -------------------------------------------------------------------------------- /solution/2.Ansible/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Install Ansible on control station 3 | ``` 4 | sudo apt-get install ansible -y 5 | ``` 6 | 7 | # Make hosts SSH accessible 8 | ``` 9 | ssh-keygen 10 | ssh-copy-id node1 && ssh-copy-id node2 && ssh-copy-id node3 11 | ``` 12 | 13 | 14 | ### Test ansible 15 | ``` 16 | ansible nodes -i myhosts -m command -a hostname 17 | ``` 18 | 19 | ### Install Python 20 | ``` 21 | ansible nodes -i myhosts -m command -a 'sudo apt-get -y install python-simplejson' 22 | ``` 23 | 24 | ### Run the playbook to install docker 25 | ``` 26 | ansible-playbook -i myhosts -K playbook1.yml 27 | ``` 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /solution/2.Ansible/myhosts: -------------------------------------------------------------------------------- 1 | [control] 2 | control 3 | 4 | [nodes] 5 | node1 6 | node2 7 | node3 -------------------------------------------------------------------------------- /solution/2.Ansible/playbook1.yml: -------------------------------------------------------------------------------- 1 | - hosts: nodes 2 | become: yes 3 | tasks: 4 | - name: ensure docker is installed 5 | apt: 6 | name: docker.io 7 | state: latest 8 | 9 | - name: ensure docker is installed 10 | apt: 11 | name: docker-compose 12 | state: latest 13 | 14 | - name: Added user to docker group 15 | user: 16 | name: vagrant 17 | groups: docker -------------------------------------------------------------------------------- /solution/3.Docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7-alpine 2 | WORKDIR /code 3 | ENV FLASK_APP=app.py 4 | ENV FLASK_RUN_HOST=0.0.0.0 5 | RUN apk add --no-cache gcc musl-dev linux-headers 6 | COPY requirements.txt requirements.txt 7 | RUN pip install -r requirements.txt 8 | EXPOSE 5000 9 | COPY . . 10 | CMD ["flask", "run"] -------------------------------------------------------------------------------- /solution/3.Docker/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Test Docker 4 | Log into node1 and test to make sure docker is working. 5 | 6 | ``` 7 | docker run hello-world 8 | ``` 9 | 10 | ### Test docker-compose app 11 | ``` 12 | docker-compose up 13 | ``` 14 | 15 | 16 | ## Troubleshooting 17 | Sometimes if you made a mistake in one of the files, you made have to re-do the image build with docker-compose build 18 | ``` 19 | docker-compose build 20 | ``` 21 | 22 | # Testing 23 | ``` 24 | curl node1:5000 25 | ``` 26 | -------------------------------------------------------------------------------- /solution/3.Docker/app.py: -------------------------------------------------------------------------------- 1 | import socket 2 | from flask import Flask 3 | 4 | app = Flask(__name__) 5 | 6 | 7 | @app.route('/') 8 | def hello(): 9 | hostname = socket.gethostname() 10 | return 'Hello World! I am {}\n'.format(hostname) -------------------------------------------------------------------------------- /solution/3.Docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.3" 2 | services: 3 | web: 4 | build: . 5 | ports: 6 | - "5000:5000" 7 | -------------------------------------------------------------------------------- /solution/3.Docker/requirements.txt: -------------------------------------------------------------------------------- 1 | flask 2 | redis -------------------------------------------------------------------------------- /solution/4.DockerSwarm/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Clone the ansible project 4 | ``` 5 | git clone https://github.com/devopsjourney1/ansible-swarm-playbook 6 | ``` 7 | *Note I had to change eth0 to eth1 in this, since ip address didn't match. 8 | 9 | 10 | # Verify docker swarm is setup. 11 | ``` 12 | sudo docker node ls 13 | ``` 14 | 15 | ``` 16 | sudo docker stack ls 17 | sudo docker ps 18 | sudo docker-compose down 19 | ``` 20 | # Migrate your app 21 | * Copy over 3.Docker folder to a new app folder 22 | 23 | ``` 24 | docker build -t devopsjourney1/myflaskimg:1 . 25 | ``` 26 | * modify docker-compose file to use image instead of build 27 | ``` 28 | docker stack deploy --compose-file docker-compose.yml myapp 29 | ``` 30 | 31 | ``` 32 | docker stack ls 33 | docker stack services myapp 34 | docker service logs -f myapp_web 35 | docker service ps myapp_web 36 | docker service update --force myapp_web 37 | docker service rm disml3ux1mye 38 | docker stack deploy --compose-file docker-compose.yml myapp 39 | curl node1:5000 40 | docker service scale myapp_web=3 41 | ``` 42 | 43 | * change image to devopsjourney1/myflaskimg:1 44 | 45 | 46 | docker service rm pky4n44z0790 47 | docker stack deploy --compose-file docker-compose.yml myapp 48 | docker service scale myapp_web=5 49 | docker service ls 50 | docker service ps myapp_web 51 | 52 | 53 | docker stack rm myapp 54 | docker network create --driver overlay --attachable --subnet 192.168.35.0/24 myoverlay 55 | docker network ls 56 | 57 | docker stack deploy --compose-file docker-compose.yml myapp 58 | docker service inspect --format '{{json .Endpoint.VirtualIPs}}' myapp_web | jq '.' 59 | 60 | docker container run --rm --network myapp_myoverlay tutum/dnsutils ping 10.0.12.6 -------------------------------------------------------------------------------- /solution/4.DockerSwarm/myapp/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7-alpine 2 | WORKDIR /code 3 | ENV FLASK_APP=app.py 4 | ENV FLASK_RUN_HOST=0.0.0.0 5 | RUN apk add --no-cache gcc musl-dev linux-headers 6 | COPY requirements.txt requirements.txt 7 | RUN pip install -r requirements.txt 8 | EXPOSE 5000 9 | COPY . . 10 | CMD ["flask", "run"] -------------------------------------------------------------------------------- /solution/4.DockerSwarm/myapp/app.py: -------------------------------------------------------------------------------- 1 | import socket 2 | from flask import Flask 3 | 4 | app = Flask(__name__) 5 | 6 | 7 | @app.route('/') 8 | def hello(): 9 | hostname = socket.gethostname() 10 | return 'Hello World! I am {}\n'.format(hostname) -------------------------------------------------------------------------------- /solution/4.DockerSwarm/myapp/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.3" 2 | services: 3 | web: 4 | image: devopsjourney1/myflaskimg:1 5 | ports: 6 | - "5000:5000" 7 | -------------------------------------------------------------------------------- /solution/4.DockerSwarm/myapp/requirements.txt: -------------------------------------------------------------------------------- 1 | flask -------------------------------------------------------------------------------- /solution/Vagrantfile: -------------------------------------------------------------------------------- 1 | Vagrant.configure("2") do |config| 2 | servers=[ 3 | { 4 | :hostname => "control", 5 | :box => "bento/ubuntu-18.04", 6 | :ip => "172.16.1.50", 7 | :ssh_port => '2200' 8 | }, 9 | { 10 | :hostname => "node1", 11 | :box => "bento/ubuntu-18.04", 12 | :ip => "172.16.1.51", 13 | :ssh_port => '2201' 14 | }, 15 | { 16 | :hostname => "node2", 17 | :box => "bento/ubuntu-18.04", 18 | :ip => "172.16.1.52", 19 | :ssh_port => '2202' 20 | }, 21 | { 22 | :hostname => "node3", 23 | :box => "bento/ubuntu-18.04", 24 | :ip => "172.16.1.53", 25 | :ssh_port => '2203' 26 | } 27 | ] 28 | 29 | servers.each do |machine| 30 | config.vm.define machine[:hostname] do |node| 31 | node.vm.box = machine[:box] 32 | node.vm.hostname = machine[:hostname] 33 | node.vm.network :private_network, ip: machine[:ip] 34 | node.vm.network "forwarded_port", guest: 22, host: machine[:ssh_port], id: "ssh" 35 | node.vm.provider :virtualbox do |vb| 36 | vb.customize ["modifyvm", :id, "--memory", 512] 37 | vb.customize ["modifyvm", :id, "--cpus", 1] 38 | end 39 | end 40 | end 41 | end -------------------------------------------------------------------------------- /solution/hosts: -------------------------------------------------------------------------------- 1 | 127.0.0.1 localhost 2 | 127.0.1.1 vagrant.vm vagrant 3 | 4 | # The following lines are desirable for IPv6 capable hosts 5 | ::1 localhost ip6-localhost ip6-loopback 6 | ff02::1 ip6-allnodes 7 | ff02::2 ip6-allrouters 8 | 9 | 172.16.1.50 control 10 | 172.16.1.51 node1 11 | 172.16.1.52 node2 12 | 172.16.1.53 node3 --------------------------------------------------------------------------------