running docker in development & production (#ndcoslo 2015)
TRANSCRIPT
Running Docker in Development & Production@[email protected]
Who?
@Ben_Hall
Tech Support > Tester > Developer > Founder / Freelancer
Agenda
• Introduction to Docker & Containers• One Container• Two Containers• Three Containers• Scale
Aim
Demonstrate steps required to create - A Multi-Container - Load Balanced - ASP.NET / Nancy / Node.js Website - Running Inside Containers via Docker
With The Lessons I Learned Along The Way
WHAT IS DOCKER?
Virtual Machine
https://www.docker.com/whatisdocker/
https://www.docker.com/whatisdocker/
Container
Own Process SpaceOwn Network InterfaceOwn Root Directories
Sandboxed
Like a lightweight VM. But it’s not a VM.
Container
Native CPUNative Memory
Native IO
No Pre-AllocationNo Performance Overheard
Container
Docker - An open platform for distributed applications for developers and sysadmins.
Otherwise known as tooling / ecosystem to run containers
Registry
Installing on OSX / Windows
https://github.com/boot2docker/
Installing In Production'curl -sSL https://get.docker.com/ | sh'
https://github.com/docker/machine
ONE CONTAINER
$ docker run
--name === Friendly name--rm === Remove when finished-t === Attach to terminal-i === Interactive
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
> docker run -d #Run In Background
elasticsearch #Image Name
https://www.dropbox.com/s/fbe8briq6ayycrh/start-elastic.gif?dl=0
Dockerfile
Dockerfile & App Source
Build
Image
https://docs.docker.com/reference/builder/
FROM
FROM benhall/aspnet-vnext-npm # Base Image
https://registry.hub.docker.com/u/benhall/aspnet-vnext-npm/
FROM microsoft/aspnet:1.0.0-beta4
RUN useradd -ms /bin/bash devRUN gpg --keyserver pool.sks-keyservers.net --recv-keys 7937DFD2AB06298B2293C3187D33FF9D0246406D 114F43EE0176B71C7BC219DD50A3051F888C628D
ENV NODE_VERSION 0.10.38ENV NPM_VERSION 2.9.1ENV APT_PACKAGES git
RUN apt-get update -qq && \ apt-get -yqq install $APT_PACKAGES && \ apt-get -yqq clean
RUN curl -SLO "http://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.gz" \ && curl -SLO "http://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \ && gpg --verify SHASUMS256.txt.asc \ && grep " node-v$NODE_VERSION-linux-x64.tar.gz\$" SHASUMS256.txt.asc | sha256sum -c - \ && tar -xzf "node-v$NODE_VERSION-linux-x64.tar.gz" -C /usr/local --strip-components=1 \ && rm "node-v$NODE_VERSION-linux-x64.tar.gz" SHASUMS256.txt.asc \ && npm install -g npm@"$NPM_VERSION" \ && npm cache clear
apt-get -y install autoconf automake build-essential libtool
run curl -SLO http://libuv.org/dist/v1.0.0/libuv-v1.0.0.tar.gz && \ tar xvf libuv-v1.0.0.tar.gz && \ rm libuv-v1.0.0.tar.gz && \ cd libuv-v1.0.0 && \ sh ./autogen.sh && \ ./configure&& \ make && \ make install && \ cd .. && \ rm -rf libuv-v1.0.0 && \ ldconfig
RUN npm install -g bower grunt-cli
USER devWORKDIR /home/dev
Dockerfile – ADD / WORKDIR / RUN
COPY WebApplication /app
WORKDIR /app
RUN ["dnu", "restore”]
Dockerfile – EXPOSE / CMD
EXPOSE 5000
CMD ["dnx", ".", "kestrel"]
Example – ASP.NET vNextFROM benhall/aspnet-vnext-npm
COPY WebApplication /app
WORKDIR /app
RUN ["dnu", "restore”]
EXPOSE 5000
CMD ["dnx", ".", "kestrel"]
Example - NancyFXFROM benhall/docker-mono
COPY . /src
WORKDIR /src
RUN xbuild Nancy.Demo.Hosting.Docker.sln
EXPOSE 8080
CMD ["mono", "src/bin/Nancy.Demo.Hosting.Docker.exe"]
Example – Node.JSFROM node:0.10.38
RUN mkdir -p /usr/src/appWORKDIR /usr/src/app
COPY package.json /usr/src/app/RUN npm install
COPY . /usr/src/app
EXPOSE 3001
CMD [ "npm", "start" ]
$ docker build--t === Friendly name.
<Docker Hub Username>/<ProjectName>:<tag>
$ docker images
> cat .dockerignore #Ignore file in root
all_the_passwords.txt.git/node_modules/bower_components/
$ docker run
$ docker ps-a === Show all containers
> docker inspect elasticsearch
"NetworkSettings": { "Bridge": "docker0", "Gateway": "172.17.42.1", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "IPAddress": "172.17.0.3", "IPPrefixLen": 16, "IPv6Gateway": "", "LinkLocalIPv6Address": "fe80::42:acff:fe11:3", "LinkLocalIPv6PrefixLen": 64, "MacAddress": "02:42:ac:11:00:03", "PortMapping": null}
$ docker run –p $CONTAINERPORT
> iptables -t nat -L –n
Chain DOCKER (1 references)target prot opt source destinationDNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:49163 to:172.17.0.27:80DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:49164 to:172.17.0.29:3000DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:49165 to:172.17.0.30:80DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:49166 to:172.17.0.31:3000DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:49167 to:172.17.0.38:80DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:49168 to:172.17.0.40:3000DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 to:172.17.0.95:80
> docker run -d #Run In Background -p 9200:9200 -p 9300:9300 #Bind Ports
elasticsearch #Image Name
https://www.dropbox.com/s/fbe8briq6ayycrh/start-elastic.gif?dl=0
> curl b2d:9200 # b2d is my Boot2Docker VM
https://www.dropbox.com/s/fbe8briq6ayycrh/start-elastic.gif?dl=0
Recap
• docker registry• docker run elasticsearch
• Create Dockerfile• docker build –t image-name .• docker run image-name
Go Lang
> cat DockerfileFROM golang:onbuild
> cat MakefileNAME = ocelotuproar/docker-outdatedbuild:
docker build -t $(NAME) .run:
docker run --rm --name $(INSTANCE) $(NAME)
> make build # Run Golang Compiler & Build
container> make run # Run built application
Private NPM Repository
https://github.com/BenHall/docker-local-npm-
registry
> docker run -d -v $(pwd)/config.yaml:/opt/sinopia/config.yaml -p 4873:4873 keyvanfatehi/sinopia:latest
> npm set registry http://b2d:4873> npm adduser --registry http://b2d:4873
RStudio
• docker run -d -p 8787:8787 rocker/rstudio
TWO CONTAINERS / PRODUCTION
Docker Push / Pull
> docker run -p 5000:5000 registry:2.0
> docker push myreg:5000/benhall/aspnet:20150617140759
> docker pull myreg:5000/benhall/aspnet:20150617140759
Persisting Data$ docker run –v <host-dir>:<container-dir> image
-v /opt/docker/elasticsearch:/data
-v /opt/docker/mysql:/var/lib/mysql
-v /docker/scrapbook/uploads:/app/public/uploads
-v $(PWD):/host
-v /var/log/syslog:/var/log/syslog
> docker run -d --restart=always # Restart if exits non-zero
redis
Environment Variables
> docker run -d -p 9200:9200 -p 9300:9300 --name es # 1) Friendly Name
elasticsearch > docker run –it –p 3000
--link es:elasticsearch #2) <container>:<alias> your-application> cat /etc/hosts172.17.0.79 elasticsearch
> envHOSTNAME=2f3b959b13a0ELASTICSEARCH_PORT=tcp://172.17.0.79:9200ELASTICSEARCH_PORT_9200_TCP=tcp://172.17.0.79:9200ELASTICSEARCH_PORT_9200_TCP_ADDR=172.17.0.79ELASTICSEARCH_PORT_9200_TCP_PORT=9200ELASTICSEARCH_PORT_9200_TCP_PROTO=tcpELASTICSEARCH_NAME=/scrapbookv2_web_1/esNODE_ENV=production
Two Websites On Port 80?
Nginx
Problematic Approach
> docker run -d --name nginx_root --link blog_benhall-1:blog_benhall-1 --link scrapbook-1:scrapbook-1 --link scrapbook_web_1:scrapbook_web_1 --link brownbag_web_1:brownbag_web_1 -p 80:80 -v /opt/docker/nginx/www:/data -v /opt/docker/nginx/sites:/etc/nginx/sites-enabled -v /opt/docker/nginx/logs:/var/log/nginx dockerfile/nginx
Nginx Proxyhttps://github.com/jwilder/nginx-proxy
https://www.dropbox.com/s/2f6y2frfjafc409/nginx-proxy-optimised.gif?dl=0
• -v /var/run/docker.sock:/tmp/docker.sock
• VIRTUAL_HOST=my.container.com
# HTTP 1.1 supportproxy_http_version 1.1;proxy_buffering off;proxy_set_header Host $http_host;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection $proxy_connection;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
upstream my.container.com {# agitated_hopperserver 172.17.0.35:5001;
}
server {listen 80;server_name my.container.com;
location / {proxy_pass http://my.container.com;
}}
> docker run -d --name blog_benhall_varnish --link blog_benhall:wordpress -e VIRTUAL_HOST=blog.benhall.me.uk -e VARNISH_BACKEND_PORT=80 -e VARNISH_BACKEND_HOST=wordpress benhall/docker-varnish
NginxVarnish
blog_benhall_varnish
Wordpressblog_benhall
THREE CONTAINERS
> cat docker-compose.ymlweb: # Container Name build: . # Build links: # Links - elasticsearch ports: # Ports - 3000 environment: # Environment VIRTUAL_HOST: 'app.joinscrapbook.com' NODE_ENV: 'production’
elasticsearch: # 2nd Container Name image: elasticsearch:1.5 # Use Image ports: # Ports - 9200:9200
> docker-compose up # Start containers–d # In background
Recreating scrapbookv2_nginx_1...Recreating scrapbookv2_redis_1...Recreating scrapbookv2_db_1...Recreating scrapbookv2_elasticsearch_1...Recreating scrapbookv2_web_1…
> docker-compose stop # Stop containersStopping scrapbookv2_web_1...Stopping scrapbookv2_elasticsearch_1...Stopping scrapbookv2_db_1...Stopping scrapbookv2_redis_1...Stopping scrapbookv2_nginx_1...
Schema Management Containers
> docker run –d # No need to bind ports --name es # Friendly Name dockerfile/elasticsearch > docker run –rm
--link es:es # Link Container:alias myapp/schema:latest # Schema Image
Sidekick Container For Testing
> docker run –d # No need to bind ports --name es # Friendly Name dockerfile/elasticsearch > docker run –it
--link es:es # Link Container:alias benhall/curl # Curl Image curl http://es:9200 # Ping service
> echo $? # Exit Code0 # Success
FOUR AND MORE! SCALE!
[tag.]<service>.service[.datacenter][.domain]
$ ping redis.service.east-aws.consul
$ ping redis.service.consul
A Load Balanced ASP.NET/NancyFX/Node.js Website running inside Docker
https://www.dropbox.com/s/gbcifo094c9v8ar/nancy-lb-demo-optimised.gif?dl=0
1) Docker raises events when containers start / stop
2) Registrator listens to events adds the new container’s details into Consul
3) Consul links container’s IP / Ports to DNS names & discovery API
> ping redis.service.consul
4) Nginx uses Consul discovery API to write & load config
SwarmA Docker-native clustering system
http://12factor.net/
THE FUTURE?
Docker and Microsoft Partnership
SQL Server as a Container?
Spoon.NET
Visual Studio as a Container?
Docker as a Platform
http://www.joinscrapbook.com
IN SUMMARY…
Only tool I use for deployment
• Close gap between development and production
• Everything is a container!
• Docker Machine, Compose & Swarm
• Running platforms like Logstash, ElasticSearch, Redis, EventStore, RavenDB, NancyFX etc? Consider containers for deployment.
Thank you
http://www.JoinScrapbook.com
2 Day Training in Oslo with ProgramUtviklingSeptember 2015