├── iamproxy ├── sv-iamproxy-log-run ├── sv-iamproxy-run └── iamproxy.py ├── emulate-amazon-linux.yml ├── iamproxy.yml ├── README.md ├── Vagrantfile └── docker-host.yml /iamproxy/sv-iamproxy-log-run: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec svlogd -tt ./main 3 | -------------------------------------------------------------------------------- /iamproxy/sv-iamproxy-run: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | exec 2>&1 4 | export PATH=/opt/iamproxy:$PATH 5 | cd /opt/iamproxy 6 | exec chpst -u root -U root -e "/opt/iamproxy/env" python iamproxy.py 7 | -------------------------------------------------------------------------------- /emulate-amazon-linux.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | sudo: yes 4 | tasks: 5 | - name: Create the ec2-user 6 | user: name=ec2-user comment="The ec2 user" group=wheel 7 | - lineinfile: 8 | dest: /etc/sudoers 9 | state: present 10 | regexp: '^%wheel' 11 | line: '%wheel ALL=(ALL) NOPASSWD: ALL' 12 | 13 | - name: Set fake ip address 14 | set_fact: 15 | ansible_ec2_local_ipv4: "{{ ansible_eth0.ipv4.address }}" 16 | docker_api_version: '1.3.2' 17 | - name: yum install packages 18 | yum: pkg={{ item }} state=present enablerepo=epel 19 | with_items: 20 | - openssh-clients 21 | - python-crypto 22 | - python-crypto2.6 23 | - python-devel 24 | - name: setup ansible 25 | pip: name="{{ item }}" state=present 26 | with_items: 27 | - 'boto>=2.32.1' 28 | - 'ansible>=1.8,<1.9' 29 | 30 | - include: ansible-balanced-stalk-docker/bootstrap.yml -------------------------------------------------------------------------------- /iamproxy/iamproxy.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import json 3 | import os 4 | 5 | from flask import Flask 6 | 7 | app = Flask(__name__) 8 | 9 | app.logger.info('env: \n%s', os.environ) 10 | 11 | 12 | def date_to_str(timestamp): 13 | return timestamp.strftime('%Y-%m-%dT%H:%M:%SZ') 14 | 15 | 16 | @app.route("/latest/meta-data/iam/security-credentials/") 17 | @app.route("/latest/meta-data/iam/security-credentials/") 18 | def role_name(role_name=None): 19 | app.logger.info('Got request for role: %s', role_name) 20 | utc_now = datetime.datetime.utcnow() 21 | thirty_day_expiration = datetime.timedelta(days=30) 22 | return json.dumps({ 23 | "Code" : "Success", 24 | "LastUpdated" : date_to_str(utc_now), 25 | "Type" : "AWS-HMAC", 26 | "AccessKeyId" : os.environ['AWS_ACCESS_KEY_ID'], 27 | "SecretAccessKey" : os.environ['AWS_SECRET_ACCESS_KEY'], 28 | "Token" : None, 29 | "Expiration" : date_to_str(utc_now + thirty_day_expiration) 30 | }) 31 | 32 | 33 | if __name__ == "__main__": 34 | app.run(port=80) 35 | -------------------------------------------------------------------------------- /iamproxy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: docker-host 3 | sudo: yes 4 | tasks: 5 | - name: Installing runit and git 6 | apt: name="{{ item }}" state=present 7 | with_items: 8 | - runit 9 | - git 10 | 11 | - name: install flask 12 | pip: name=flask==0.10.1 state=present 13 | 14 | - name: copy file 15 | copy: src=iamproxy dest=/opt mode=0744 16 | 17 | - name: create secret environment dir 18 | file: dest=/opt/iamproxy/env state=directory mode=0755 19 | 20 | - name: write secret environment variables 21 | copy: content={{ lookup('env', item) }} dest=/opt/iamproxy/env/{{ item }} 22 | with_items: 23 | - AWS_ACCESS_KEY_ID 24 | - AWS_SECRET_ACCESS_KEY 25 | 26 | - name: /etc/service directory creation 27 | file: path=/etc/service/{{ item }} state=directory 28 | with_items: 29 | - iamproxy 30 | - iamproxy/log 31 | - iamproxy/log/main 32 | 33 | - name: copy installation 34 | copy: > 35 | src=iamproxy/{{ item.key }} 36 | dest=/etc/service/iamproxy/{{ item.value}} 37 | mode=0744 38 | with_items: 39 | - key: sv-iamproxy-run 40 | value: run 41 | - key: sv-iamproxy-log-run 42 | value: log/run 43 | 44 | - name: route 169.254.169.254 to 127.0.0.1 45 | shell: > 46 | iptables -t nat -I OUTPUT -p tcp \ 47 | -d 169.254.169.254 \ 48 | --dport 80 -j DNAT \ 49 | --to-destination 127.0.0.1:80 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docker-host 2 | 3 | `docker-host` uses `Vagrant` to provide an experience similar to [boot2docker](http://boot2docker.io/), and serves as a seamless layer for interacting w/ docker through the host operating system. 4 | 5 | `docker-host` has a **very simple** ansible playbook called `docker-host.yml` that configures the the docker daemon living in the `docker-host` as well as sets up a seamless private network to interact with the `docker-host` through the host operating system -- OSX and Linux systems are supported only for now. 6 | 7 | The main purpose of `docker-host` is to essentially serve a virtual machine that runs the docker daemon. This becomes the basis of an execution environment for all docker images, used in the instructions further below, in which a shared virtual machine executes all the docker images and exposes them via the host machine's command-line client. 8 | 9 | 10 | ## Instructions 11 | 12 | ### OSX 13 | 14 | To get started, on your host system, you need: 15 | 16 | - Ansible 1.8.2+ 17 | - Vagrant 1.7+ 18 | - docker v1.6.0 19 | 20 | #### brew commands 21 | - `brew install ansible` 22 | - `brew cask install vagrant` 23 | - `vagrant plugin install nugrant` 24 | - `brew install docker` 25 | 26 | ### LINUX 27 | 28 | (todo) 29 | 30 | ## Play 31 | 32 | Then, `vagrant up docker-host` - wait until it's done. 33 | 34 | Then, `export DOCKER_HOST=10.2.0.10:2375` (probably should put that in your `${shell}rc` or `${shell}`profile). 35 | 36 | To test a successful installation, type in `docker ps` from your host machine cli and you should see: 37 | 38 | ```bash 39 | mahmoud@gauss:15/04/08,11:09 λ ~ rb:1.9.3-p286 40 | ❯❯❯ uname -a ⏎ 41 | Darwin gauss 14.1.0 Darwin Kernel Version 14.1.0: Thu Feb 26 19:26:47 PST 2015; root:xnu-2782.10.73~1/RELEASE_X86_64 x86_64 42 | 43 | mahmoud@gauss:15/04/08,11:09 λ ~ rb:1.9.3-p286 44 | ❯❯❯ docker ps 45 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 46 | ``` 47 | 48 | When done provisioning, `docker login` to set credentials. 49 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.require_version '>= 1.6.5' 5 | 6 | unless Vagrant.has_plugin?('nugrant') 7 | warn "[\e[1m\e[31mERROR\e[0m]: Please run: vagrant plugin install nugrant" 8 | exit -1 9 | end 10 | 11 | BRIDGE_NETWORK = '10.2.0.10' 12 | BRIDGE_NETMASK = '255.255.0.0' 13 | 14 | # Setup Defaults 15 | # 16 | # Sets up defaults for vagrant-nugrant 17 | # 18 | # @return hash with defaults 19 | def setup_defaults() 20 | { 21 | 'box' => { 22 | 'memory' => '2048', 23 | 'cpus' => '2' 24 | } 25 | } 26 | end 27 | 28 | 29 | Vagrant.configure(2) do |config| 30 | 31 | config.user.defaults = setup_defaults 32 | 33 | # sudo route -n add -net 172.17.0.0 10.2.0.10 34 | # sudo route -nv add -net 192.168.59 -interface vboxnet1 35 | # # OSX 36 | # $> sudo route -n add -net 172.17.0.0 10.2.0.10 37 | # Linux (untested) 38 | # $> sudo route -net 172.17.0.0 netmask 255.255.0.0 gw 10.2.0.10 39 | 40 | config.vm.define 'docker-host', {:primary => true} do |dh| 41 | 42 | if Vagrant.has_plugin?('vagrant-cachier') 43 | dh.cache.enable :generic, {"docker" => { cache_dir: "/cache-docker" }} 44 | end 45 | 46 | dh.vm.box = 'ubuntu/trusty64' 47 | # http://stackoverflow.com/a/19758886/133514 48 | # Disable the default synced folder 49 | dh.vm.synced_folder '.', '/vagrant', :disabled => true 50 | dh.vm.network :private_network, :ip => BRIDGE_NETWORK, :netmask => BRIDGE_NETMASK 51 | dh.vm.network "forwarded_port", :guest => 2375, :host => 2375 52 | dh.vm.provider :virtualbox do |vb| 53 | # The --nicpromisc2 translates to Promiscuous mode for nic2, where nic2 -> eth1. 54 | # So --nocpromisc3 would change that setting for eth2, etc. 55 | vb.customize ["modifyvm", :id, "--nicpromisc2", "allow-all"] 56 | vb.memory = config.user.box.memory 57 | vb.cpus = config.user.box.cpus 58 | end 59 | 60 | dh.vm.provision 'ansible' do |ansible| 61 | ansible.playbook = 'docker-host.yml' 62 | ansible.host_key_checking = false 63 | ansible.verbose = 'vvv' 64 | ansible.extra_vars = { 65 | :bridge_network => BRIDGE_NETWORK, 66 | :bridge_netmask => BRIDGE_NETMASK, 67 | :local_user => ENV['USER'] 68 | } 69 | end 70 | 71 | end 72 | 73 | config.vm.define 'centos-docker-host', {:autostart => false} do |rhdh| 74 | rhdh.vm.box = 'chef/centos-6.5' 75 | rhdh.vm.synced_folder '.', '/vagrant', :disabled => true 76 | rhdh.vm.network :private_network, :ip => BRIDGE_NETWORK, :netmask => BRIDGE_NETMASK 77 | rhdh.vm.network "forwarded_port", :guest => 2375, :host => 2375 78 | rhdh.vm.provider :virtualbox do |vb| 79 | # The --nicpromisc2 translates to Promiscuous mode for nic2, where nic2 -> eth1. 80 | # So --nocpromisc3 would change that setting for eth2, etc. 81 | vb.customize ["modifyvm", :id, "--nicpromisc2", "allow-all"] 82 | end 83 | 84 | rhdh.vm.provision 'ansible' do |ansible| 85 | ansible.playbook = 'docker-host.yml' 86 | ansible.host_key_checking = false 87 | ansible.extra_vars = { 88 | :bridge_network => BRIDGE_NETWORK, 89 | :bridge_netmask => BRIDGE_NETMASK, 90 | :local_user => ENV['USER'] 91 | } 92 | end 93 | # 94 | # rhdh.vm.provision 'ansible' do |ansible| 95 | # ansible.playbook = 'emulate-amazon-linux.yml' 96 | # ansible.host_key_checking = false 97 | # ansible.extra_vars = { 98 | # :AWS_ACCESS_KEY_ID => ENV['AWS_ACCESS_KEY_ID'], 99 | # :AWS_SECRET_ACCESS_KEY => ENV['AWS_SECRET_ACCESS_KEY'] 100 | # } 101 | # end 102 | end 103 | 104 | # config.vm.provision 'ansible' do |ansible| 105 | # ansible.playbook = 'iamproxy.yml' 106 | # ansible.host_key_checking = false 107 | # ansible.extra_vars = { 108 | # :AWS_ACCESS_KEY_ID => ENV['AWS_ACCESS_KEY_ID'], 109 | # :AWS_SECRET_ACCESS_KEY => ENV['AWS_SECRET_ACCESS_KEY'] 110 | # } 111 | # end 112 | 113 | # The following line terminates all ssh connections. Therefore 114 | # Vagrant will be forced to reconnect. 115 | # That's a workaround to have the docker command in the PATH and 116 | # add Vagrant to the docker group by logging in/out 117 | config.vm.provision 'shell', :inline => 118 | "ps aux | grep 'sshd:' | awk '{print $2}' | xargs kill" 119 | 120 | end 121 | -------------------------------------------------------------------------------- /docker-host.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # With massive help from: 3 | # - https://github.com/bryfry/ansible-docker/blob/master/docker.yml 4 | # - https://github.com/bobbyrenwick/ansible-pip/blob/master/tasks/main.yml 5 | - hosts: all 6 | sudo: yes 7 | 8 | vars: 9 | docker_host_ip: 0.0.0.0 10 | docker_host_port: 2375 11 | docker_version: 1.7.0 12 | docker_py_version: 1.2.3 13 | python: python 14 | pip: pip 15 | pip_version: 16 | pip_download_dest: /tmp 17 | tasks: 18 | - name: Ubuntu | Adding Docker repository key 19 | apt_key: > 20 | url="https://get.docker.io/gpg" id="A88D21E9" state=present 21 | when: ansible_os_family == 'Debian' 22 | 23 | - name: Ubuntu | Adding Docker repository 24 | apt_repository: > 25 | repo='deb http://get.docker.io/ubuntu docker main' 26 | update_cache=yes 27 | state=present 28 | when: ansible_os_family == 'Debian' 29 | 30 | - name: Ubuntu | Installing Docker and Dependencies 31 | apt: name="{{ item }}" state=present 32 | with_items: 33 | - apt-transport-https 34 | - "lxc-docker-{{ docker_version }}" 35 | when: ansible_os_family == 'Debian' 36 | 37 | - name: Ubuntu | Remove system pip if it exists 38 | apt: name=python-pip state=absent 39 | when: ansible_os_family == 'Debian' 40 | 41 | - name: check to see if pip is already installed 42 | command: "{{ pip }} --version" 43 | ignore_errors: true 44 | changed_when: false 45 | register: pip_is_installed 46 | changed_when: false 47 | 48 | - name: download pip 49 | get_url: url=https://bootstrap.pypa.io/get-pip.py dest={{ pip_download_dest }} 50 | when: pip_is_installed.rc != 0 51 | 52 | - name: install pip 53 | command: "{{ python }} {{ pip_download_dest }}/get-pip.py" 54 | sudo: yes 55 | when: pip_is_installed.rc != 0 56 | 57 | - name: check to see if pip is installed at the correct version 58 | shell: "{{ pip }} --version | awk '{print $2}'" 59 | register: pip_installed_version 60 | changed_when: false 61 | when: pip_version != None or pip_version != "LATEST" 62 | 63 | - name: install required version of pip 64 | command: "{{ pip }} install pip=={{ pip_version }}" 65 | sudo: yes 66 | when: pip_version != None and pip_installed_version.stdout != pip_version and pip_version != "LATEST" 67 | 68 | - name: Upgrade to latest version of pip 69 | command: "{{ pip }} install -U pip" 70 | register: pip_latest_output 71 | sudo: yes 72 | changed_when: pip_latest_output.stdout.find('Requirement already up-to-date') == -1 73 | when: pip_version == None or pip_version == "LATEST" 74 | 75 | - name: CentOS | get epel-repo rpm RHEL6 76 | get_url: 77 | dest: /tmp/epel-release.rpm 78 | url: http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm 79 | when: ansible_os_family == 'RedHat' 80 | 81 | - name: CentOS | install epel-repo rpm 82 | yum: pkg=/tmp/epel-release.rpm state=installed 83 | when: ansible_os_family == 'RedHat' 84 | register: epel_enabled 85 | 86 | - name: CentOS | update yum cache 87 | command: yum makecache 88 | when: ansible_os_family == 'RedHat' 89 | register: epel_enabled | changed 90 | 91 | - name: CentOS | Installing Docker and Dependencies 92 | yum: name={{ item }} enablerepo=epel state=present 93 | with_items: 94 | - "docker-io" 95 | - python-pip 96 | - libselinux-python 97 | when: ansible_os_family == 'RedHat' 98 | 99 | - name: Installing docker-py for ansible docker module 100 | pip: name=docker-py=={{ docker_py_version }} state=present 101 | 102 | - name: Debian | Expose docker host 103 | lineinfile: > 104 | dest=/etc/default/docker 105 | regexp="^DOCKER_OPTS" 106 | line='DOCKER_OPTS="-H unix:///var/run/docker.sock -H tcp://{{ docker_host_ip }}:{{ docker_host_port }}"' 107 | when: expose_docker_host 108 | tags: [test] 109 | when: ansible_os_family == 'Debian' 110 | 111 | - name: CentOS | Expose docker host 112 | lineinfile: 113 | dest: /etc/sysconfig/docker 114 | regexp: "^other_args" 115 | line: 'other_args="-H unix:///var/run/docker.sock -H tcp://{{ docker_host_ip }}:{{ docker_host_port }}"' 116 | when: expose_docker_host 117 | tags: [test] 118 | when: ansible_os_family == 'RedHat' 119 | 120 | - name: Restart docker service / daemon 121 | service: name=docker state=restarted 122 | 123 | 124 | - hosts: all 125 | sudo: yes 126 | vars: 127 | expose_docker_host: true 128 | squash_version: v0.0.11 129 | squash_file: "docker-squash-linux-amd64-{{ squash_version }}.tar.gz" 130 | squash_url: "https://github.com/jwilder/docker-squash/releases/download/{{ squash_version }}/{{ squash_file }}" 131 | tasks: 132 | - name: Route traffic locally to docker 133 | sudo: true 134 | sudo_user: "{{ local_user }}" 135 | shell: sudo route -nv add -net {{ ansible_docker0.ipv4.address }}/16 {{ bridge_network }} 136 | delegate_to: 127.0.0.1 137 | when: expose_docker_host 138 | tags: [test] 139 | 140 | - name: Adding vagrant user to docker group 141 | user: name=vagrant append=yes groups=docker state=present 142 | 143 | - name: download docker-squash 144 | get_url: url={{ squash_url }} dest=/tmp mode=0644 145 | 146 | - name: unpack docker-squash 147 | unarchive: src=/tmp/{{ squash_file }} dest=/usr/local/bin copy=no 148 | 149 | # - name: smash grub 150 | # lineinfile: > 151 | # dest=/etc/default/grub 152 | # regexp='^GRUB_CMDLINE_LINUX=' 153 | # line='GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"' 154 | # register: grub_edit 155 | 156 | # - name: updatin grub 157 | # command: update-grub 158 | # when: grub_edit|changed 159 | 160 | # - name: ufw forwardin 161 | # lineinfile: > 162 | # dest=/etc/default/ufw 163 | # regexp="^DEFAULT_FORWARD_POLICY=" 164 | # line="DEFAULT_FORWARD_POLICY=\"ACCEPT\"" 165 | 166 | # - name: restart machine 167 | # command: shutdown -r now "Ansible updates triggered" 168 | # async: 0 169 | # poll: 0 170 | # ignore_errors: true 171 | # when: grub_edit|changed 172 | 173 | # - name: waiting for server to come back 174 | # local_action: > 175 | # wait_for host={{ ansible_ssh_host }} 176 | # port={{ansible_ssh_port}} delay=30 state=started 177 | # sudo: false 178 | --------------------------------------------------------------------------------