├── .dockerignore ├── .gitignore ├── CONTRIBUTING.md ├── Dockerfile ├── Makefile ├── PAINFUL.md ├── README.md ├── slides ├── About_Docker │ ├── Body.md │ ├── Cover.md │ ├── How_Does_Docker_Work.md │ ├── Objectives.md │ ├── appcont.png │ ├── deploysys.png │ ├── dockerworks.jpg │ ├── elimatrix.png │ ├── heroku-first-homepage.png │ ├── history.png │ ├── image.png │ ├── layer.png │ ├── lightcont.png │ ├── matrix.png │ ├── problem.png │ ├── sepcon.png │ ├── shipeco.png │ ├── shipping.png │ ├── signup.png │ ├── superlight.png │ └── who.png ├── Ambassadors │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ ├── ambassador.jpg │ ├── diagram.odg │ └── diagram.png ├── Background_Containers │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ └── background-containers.jpg ├── Building_Images_Interactively │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ └── cmatrix.png ├── Building_Images_With_Dockerfiles │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ ├── construction.jpg │ └── webapp.png ├── Cmd_And_Entrypoint │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ ├── entrypoint.jpg │ └── webapp.png ├── Compose_For_Dev_Stacks │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ ├── composeapp.png │ ├── composeup.gif │ └── fig.png ├── Connecting_Containers_With_Links │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ ├── graph.gif │ ├── notes.png │ └── redisonrails.png ├── Container_Network_Model │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ ├── complex-network.jpg │ ├── trainingwheels-error.png │ └── trainingwheels-ok.png ├── Container_Networking_Basics │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ ├── browser.png │ ├── network.jpg │ └── web.png ├── Copying_Files_During_Build │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ ├── copy.jpg │ └── entrypoint.jpg ├── Course_Conclusion │ ├── Body.md │ ├── Cover.md │ └── end.jpg ├── Course_Overview │ ├── .DS_Store │ ├── Body.md │ ├── Cover.md │ ├── Intro.md │ ├── Objectives.md │ ├── Toc.md │ └── logo.png ├── Docker_API │ ├── Body.md │ ├── Cover.md │ └── Objectives.md ├── Docker_Hub_Advanced │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ ├── account.png │ ├── addautomated.png │ ├── addtrusted.png │ ├── configtrusted.png │ ├── frontpage.png │ ├── github.png │ ├── githublinked.png │ ├── githubrepo.png │ ├── login.png │ ├── settings.png │ ├── tags.png │ └── trainrepo.png ├── Docker_Hub_Intro │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ ├── addrepo.png │ ├── addrepo2.png │ ├── addrepo3.png │ ├── autobuild-build.png │ ├── autobuild-config.png │ ├── autobuild-config2.png │ ├── autobuild-select.png │ ├── autobuild-success.png │ ├── blankrepositories.png │ ├── collab.png │ ├── dockerhub.png │ ├── octocat.png │ ├── officialrepos.png │ ├── provider-auth.png │ ├── provider-login.png │ ├── provider-perms.png │ ├── provider.png │ ├── publicrepos.png │ ├── registerhub.png │ ├── settings.png │ └── webhooks.png ├── Docker_Hub_Tease │ ├── Body.md │ ├── Cover.md │ └── Objectives.md ├── Dockerfile_Reference │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ ├── construction.jpg │ └── webapp.png ├── First_Containers │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ ├── firstcontainers.jpg │ └── superman.png ├── Initial_Images │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ ├── docker-filesystems-multilayer.png │ ├── image.png │ └── stenciling-wall.jpg ├── Install_Docker │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ ├── install.jpg │ ├── logo.png │ └── sudo.png ├── Local_Development_Workflow │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ ├── construction.jpg │ ├── webapp1.png │ └── webapp2.png ├── Naming_And_Inspecting │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ └── containermarkings.jpg ├── Securing_With_TLS │ ├── Body.md │ ├── Cover.md │ └── Objectives.md ├── Security │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ ├── Summary.md │ └── hackers.jpg ├── Start_And_Attach │ ├── Body.md │ ├── Cover.md │ └── Objectives.md ├── Template │ ├── 1_Cover.md │ ├── 2_Objectives.md │ ├── 3_Body.md │ ├── 4_Exercises.md │ └── 5_Conclusion.md ├── Use_Training_VM │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ ├── install.jpg │ ├── logo.png │ ├── ssh.jpg │ └── sudo.png ├── Vulnerabilities │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ └── security-breach.jpg ├── Working_With_Volumes │ ├── Body.md │ ├── Cover.md │ ├── Objectives.md │ └── volume.jpg ├── _images │ ├── DockerLogo.png │ ├── exercise-sm.png │ ├── exercise.png │ ├── lab-sm.png │ ├── lab.png │ └── linen.png ├── _preshow │ ├── DockerLogo.png │ └── README ├── docker.css ├── favicon.ico ├── favicon.png ├── fonts.css ├── print.json ├── showoff.css └── showoff.json └── tools ├── README.md ├── edit-all.sh ├── extract-section-titles.py ├── find-non-ascii-7-characters.sh ├── find-orphaned-pages.sh └── make-toc.py /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | *.pdf 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *~ 3 | .DS_Store 4 | viewstats.json 5 | */_preshow/* 6 | !*/_preshow/README 7 | .ruby-version 8 | DockerSlides.pdf 9 | DockerExercises.pdf 10 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ### Conventions 4 | 5 | Fork the repo and make changes on your fork in a feature branch: 6 | 7 | - If it's a bugfix branch, name it XXX-something where XXX is the number of the 8 | issue 9 | - If it's a feature branch, create an enhancement issue to announce your 10 | intentions, and name it XXX-something where XXX is the number of the issue. 11 | 12 | ### Merge approval 13 | 14 | Docker maintainers use LGTM (looks good to me) in comments on the code review 15 | to indicate acceptance. 16 | 17 | A change requires LGTMs from at least one maintainer. 18 | 19 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | MAINTAINER Education Team at Docker 3 | 4 | RUN apt-get update 5 | RUN apt-get install -y curl wget git ruby2.0 ruby2.0-dev libxml2-dev libxslt-dev build-essential zlib1g-dev 6 | RUN ln -sf ruby2.0 /usr/bin/ruby 7 | RUN ln -sf gem2.0 /usr/bin/gem 8 | 9 | # Let's install prince. The first dpkg will fail because of missing dependencies, 10 | # so we'll install the dependencies with "install -f" then try again. 11 | WORKDIR /usr/src 12 | RUN wget http://www.princexml.com/download/prince_9.0-5_ubuntu14.04_amd64.deb 13 | RUN dpkg -i prince_9.0-5_ubuntu14.04_amd64.deb || true 14 | RUN apt-get install -fy 15 | RUN dpkg -i prince_9.0-5_ubuntu14.04_amd64.deb 16 | 17 | # Install showoff. 18 | WORKDIR /usr/src 19 | RUN git clone https://github.com/puppetlabs/showoff.git 20 | WORKDIR /usr/src/showoff 21 | RUN git checkout v0.10.2 22 | RUN gem install --no-rdoc --no-ri -v '<1.7' nokogiri 23 | RUN gem install --no-rdoc --no-ri -v '<3.0' public_suffix 24 | RUN gem build showoff.gemspec 25 | RUN gem install --no-rdoc --no-ri ./showoff-*.gem 26 | 27 | COPY /slides/ /slides/ 28 | WORKDIR /slides 29 | 30 | CMD [ "showoff", "serve" ] 31 | 32 | EXPOSE 9090 33 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TAG=$(shell git rev-parse --short HEAD) 2 | 3 | IMAGE=training/docker-fundamentals-image 4 | CONTAINER=showoff 5 | PAPER=US-Letter 6 | 7 | default: 8 | # Available targets: 9 | # - release (tag slides and run showoff) 10 | # - dev (don't tag slides; run showoff with a volume) 11 | # - pdf (generate PDF files; requires showoff container) 12 | 13 | release: 14 | # Is working directory clean? If you get an error here, run "make dev" instead. 15 | git diff-index --quiet HEAD 16 | 17 | # Add git commit id to training slides before building 18 | find . -name *.css -exec sed -i "" "s/{{DOCKER_TRAINING_VERSION}}/$(TAG)/" {} \; 19 | find . -name *.json -exec sed -i "" "s/{{DOCKER_TRAINING_VERSION}}/$(TAG)/" {} \; 20 | 21 | # Optionally set paper size 22 | find . -name *.css -exec sed -i "" "s/US-Letter/$(PAPER)/" {} \; 23 | 24 | # Build updated docker image 25 | docker build -t $(IMAGE) . 26 | 27 | # Reset to old 28 | git reset --hard HEAD 29 | 30 | # Remove the old container (if there is one) 31 | # and start a new one. 32 | docker rm -f $(CONTAINER) || true 33 | docker run -d --name $(CONTAINER) -p 9090:9090 $(IMAGE) 34 | 35 | dev: 36 | # Build updated docker image 37 | docker build -t $(IMAGE) . 38 | # Remove the old container (if there is one) 39 | docker rm -f $(CONTAINER) 2>/dev/null || true 40 | # Run container with volume to slides to make changes on the fly 41 | docker run -d --name $(CONTAINER) -v $(shell pwd)/slides:/slides -p 9090:9090 $(IMAGE) 42 | 43 | pdf: 44 | # The showoff container has to be running (through "make release" or "make dev") 45 | docker inspect --format='{{""}}' showoff 46 | docker run --rm --net container:$(CONTAINER) $(IMAGE) \ 47 | prince http://localhost:9090/print -o - > DockerSlides.pdf 48 | docker run --rm --net container:$(CONTAINER) $(IMAGE) \ 49 | prince http://localhost:9090/supplemental/exercises/print -o - > DockerExercises.pdf 50 | -------------------------------------------------------------------------------- /PAINFUL.md: -------------------------------------------------------------------------------- 1 | # Manual operation 2 | 3 | You shouldn't do this, but if you want to do it anyway, here it goes. 4 | 5 | 6 | ## Showoff 7 | 8 | You'll need the [Puppet Labs fork of 9 | Showoff](https://github.com/puppetlabs/showoff/). 10 | 11 | $ git clone https://github.com/puppetlabs/showoff.git 12 | $ cd showoff 13 | $ gem build showoff.gemspec 14 | $ sudo gem install ./showoff-*.gem 15 | 16 | Showoff is tested with Ruby 1.8.7, 1.9.3, and 2.0. It should install 17 | cleanly on these versions. 18 | 19 | To run the training: 20 | 21 | $ showoff serve 22 | 23 | You should be able to see the slides at: 24 | 25 | http://localhost:9090 26 | 27 | You will be able to see the exercises at: 28 | 29 | http://localhost:9090/supplemental/exercises 30 | 31 | 32 | ### Generating PDFs 33 | 34 | 1. Install PrinceXML - http://www.princexml.com/download/ 35 | 2. Launch Showoff - `showoff server` 36 | 3. Browse to the /print URLs. 37 | 38 | http://localhost:9090/print 39 | http://localhost:9090/supplemental/exercises/print 40 | 41 | 4. Use Prince to product the PDFs. 42 | 43 | $ prince http://localhost:9090/print -o DockerSlides.pdf 44 | $ prince http://localhost:9090/supplemental/exercises/print -o DockerExercises.pdf 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Intro to Docker 2 | 3 | This repository contains training materials for basic Docker training. 4 | 5 | # THIS CONTENT HAS BEEN MOVED TO [jpetazzo/container.training](https://github.com/jpetazzo/container.training)! 6 | 7 | I'm keeping this repo around for historical purposes but all maintenance 8 | and further development will be on container.training. 9 | 10 | 11 | ## History and relation to other training materials 12 | 13 | This course was originally written by Aaron Huslage, James Turnbull, 14 | Jérôme Petazzoni, and Nathan LeClaire (all employees of Docker Inc. at 15 | that time). It was used for a while by Docker Inc. and its authorized 16 | training partners as the "Docker Fundamentals" course. It was a 2-day, 17 | instructor-led training, covering much more ground than the current 18 | repository. 19 | 20 | Over time, the original "Docker Fundamentals" course was split into 21 | additional modules for various audiences, and it stopped being maintained 22 | by Docker Inc. A few people continued to use the first half of the course 23 | to deliver Docker workshops for underrepresentend minorities in tech, e.g. 24 | with [GoBridge](https://blog.golangbridge.org/gobridge-is-organizing-a-docker-workshop-7b8c1f5f6060#.arg46bwer), 25 | [Women Who Go](https://www.meetup.com/Women-Who-Go-Berlin/events/230021596/), 26 | [Girl Develop It](https://www.meetup.com/girldevelopit/events/233729751/), etc. 27 | 28 | The first half of the content continued to be updated by individual 29 | contributors to include new features of Docker, while the second half 30 | was removed since it wasn't useful anymore in this context. 31 | 32 | Docker Inc. agreed to make the current version of the repository public. 33 | This will allow anyone to use this content for basic Docker courses. 34 | 35 | **Please note that this material is not "official" in any way.** It derives 36 | from material that was official in 2014, but that's pretty much it! 37 | 38 | Also note that this material was designed primarily for instructor-led 39 | training. If you want to learn Docker on your own, Docker Inc. has 40 | [self-paced learning online materials]( 41 | http://training.docker.com/category/self-paced-online) as well as 42 | tons of [tutorials and hands on labs](https://github.com/docker/labs). 43 | 44 | Finally, keep in mind that this is an intro-level course. If you 45 | want to tackle more advanced topics, we invite you to check 46 | [instructor-led training sessions](http://training.docker.com/instructor-led-training) 47 | offered by Docker Inc. and its training partners. 48 | 49 | Thank you! 50 | 51 | 52 | ## Course format 53 | 54 | It uses Puppetlabs' fork of [showoff]. Showoff is a program that takes: 55 | 56 | - a JSON file, which acts as a table of contents, referencing ... 57 | - ... a number of Markdown files, which are the content of the course. 58 | 59 | Showoff will be installed in a container; so you need Docker to run this! 60 | 61 | 62 | ## How to use it (editor mode) 63 | 64 | Run `make dev`. Point your browser to http://localhost:9090/ (or to 65 | your Docker machine IP address, on port 9090)). 66 | 67 | The slides will be bind-mounted into the container, so you can 68 | edit them locally and showoff will (should) pickup your changes. 69 | 70 | 71 | ## How to use it (presenter mode) 72 | 73 | When delivering a training: if the students have printed material, 74 | the cover of the books should indicate the hash used to build the 75 | materials. Checkout that version, then run `make release`, 76 | and point your browser just like before. 77 | 78 | If you don't use printed materials, you can checkout master, of course. 79 | 80 | 81 | ## How to use it (generating PDF) 82 | 83 | `make release` (preferably!) or `make dev` (if you're tweaking things 84 | and don't want to commit each time...) then `make pdf`. 85 | 86 | The PDF files will be created in the current directory. Look for 87 | `DockerSlides.pdf` and `DockerExercises.pdf`. They should be tagged 88 | with the git hash corresponding to their source revision. 89 | 90 | 91 | ## Training VMs 92 | 93 | The materials assume that each attendee receives a cloud instance, 94 | pre-installed to have the latest version of Docker and a few other 95 | helpful things installed. 96 | 97 | These instances can be created automatically using scripts located 98 | in another repository, [jpetazzo/orchestration-workshop/prepare-vms]( 99 | https://github.com/jpetazzo/orchestration-workshop/tree/master/prepare-vms). 100 | This will require an AWS account with a credit card. 101 | 102 | You can also do some minor adaptations and use [Play-With-Docker]( 103 | http://play-with-docker.com/) instead. 104 | 105 | 106 | ## Other tools 107 | 108 | The [tools](tools) directory has a bunch of various useful scripts. 109 | 110 | 111 | ## Manual operation 112 | 113 | If you want to run showoff or print PDFs locally, check 114 | [PAINFUL.md](PAINFUL.md) for instructions. 115 | 116 | 117 | ## Feedback 118 | 119 | Please report problems, typos, etc. by opening GitHub issues on this 120 | repository. The unofficial maintainer of this repo is @jpetazzo. 121 | 122 | 123 | [showoff]: https://github.com/puppetlabs/showoff 124 | 125 | 126 | -------------------------------------------------------------------------------- /slides/About_Docker/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # Elevator pitch 3 | 4 | ## (for your manager, boss...) 5 | 6 | 7 | # OK... Why the buzz around containers? 8 | 9 | * The software industry has changed. 10 | * Before: 11 | * monolithic applications 12 | * long development cycles 13 | * single environment 14 | * slowly scaling up 15 | * Now: 16 | * decoupled services 17 | * fast, iterative improvements 18 | * multiple environments 19 | * quickly scaling out 20 | 21 | 22 | # Deployment becomes very complex 23 | 24 | * Many different stacks: 25 | * languages 26 | * frameworks 27 | * databases 28 | * Many different targets: 29 | * individual development environments 30 | * pre-production, QA, staging... 31 | * production: on prem, cloud, hybrid 32 | 33 | 34 | # The deployment problem 35 | 36 | ![problem](problem.png) 37 | 38 | 39 | # The Matrix from Hell 40 | 41 | ![matrix](matrix.png) 42 | 43 | 44 | # An inspiration and some ancient history! 45 | 46 | ![history](history.png) 47 | 48 | 49 | # Intermodal shipping containers 50 | 51 | ![shipping](shipping.png) 52 | 53 | 54 | # This spawned a Shipping Container Ecosystem! 55 | 56 | ![shipeco](shipeco.png) 57 | 58 | 59 | # A shipping container system for applications 60 | 61 | ![shipapp](appcont.png) 62 | 63 | 64 | # Eliminate the matrix from Hell 65 | 66 | ![elimatrix](elimatrix.png) 67 | 68 | 69 | # Results 70 | 71 | * Dev-to-prod reduced from 9 months to 15 minutes (ING) 72 | 73 | * Continuous integration job time reduced by more than 60% (BBC) 74 | 75 | * Dev-to-prod reduced from weeks to minutes (GILT) 76 | 77 | 78 | # Elevator pitch 79 | 80 | ## (for your fellow devs and ops) 81 | 82 | 83 | # Escape dependency hell 84 | 85 | 1. Write installation instructions into an "INSTALL.txt" file 86 | 2. Using this file, write an "install.sh" script that works *for you* 87 | 3. Turn this file into a "Dockerfile", test it on your machine 88 | 4. If the Dockerfile builds on your machine, it will build *anywhere* 89 | 5. Rejoice as you escape dependency hell and "works on my machine" 90 | 91 | Never again "worked in dev - ops problem now!" 92 | 93 | 94 | # On-board developers and contributors rapidly 95 | 96 | 1. Write Dockerfiles for your application components 97 | 2. Use pre-made images from the Docker Hub (mysql, redis...) 98 | 3. Describe your stack with a Compose file 99 | 4. On-board somebody with two commands: 100 | 101 | @@@ 102 | git clone ... 103 | docker-compose up 104 | 105 | Also works to create dev, integration, QA environments in minutes! 106 | 107 | 108 | # Implement reliable CI easily 109 | 110 | 1. Build test environment with a Dockerfile or Compose file 111 | 2. For each test run, stage up a new container or stack 112 | 3. Each run is now in a clean environment 113 | 4. No pollution from previous tests 114 | 115 | Way faster and cheaper than creating VMs each time! 116 | 117 | 118 | # Use container images as build artefacts 119 | 120 | 1. Build your app from Dockerfiles 121 | 2. Store the resulting images in a registry 122 | 3. Keep them forever (or as long as necessary) 123 | 4. Test those images in QA, CI, integration... 124 | 5. Run the same images in production 125 | 6. Something goes wrong? Rollback to previous image 126 | 7. Investigating old regression? Old image has your back! 127 | 128 | Images contain all the libraries, dependencies, etc. needed to run the app. 129 | 130 | 131 | # Decouple "plumbing" from application logic 132 | 133 | 1. Write your code to connect to named services ("db", "api"...) 134 | 2. Use Compose to start your stack 135 | 3. Docker will setup per-container DNS resolver for those names 136 | 4. You can now scale, add load balancers, replication ... without changing your code 137 | 138 | Note: this is not covered in this intro level workshop! 139 | 140 | 141 | 142 | # What did Docker bring to the table? 143 | 144 | ## Docker before/after 145 | 146 | 147 | # Formats and APIs, before Docker 148 | 149 | * No standardized exchange format. 150 |
(No, a rootfs tarball is *not* a format!) 151 | * Containers are hard to use for developers. 152 |
(Where's the equivalent of `docker run debian`?) 153 | * As a result, they are *hidden* from the end users. 154 | * No re-usable components, APIs, tools. 155 |
(At best: VM abstractions, e.g. libvirt.) 156 | 157 | Analogy: 158 | 159 | * Shipping containers are not just steel boxes. 160 | * They are steel boxes that are a standard size, 161 |
with the same hooks and holes. 162 | 163 | 164 | # Formats and APIs, after Docker 165 | 166 | * Standardize the container format, because containers were not portable. 167 | * Make containers easy to use for developers. 168 | * Emphasis on re-usable components, APIs, ecosystem of standard tools. 169 | * Improvement over ad-hoc, in-house, specific tools. 170 | 171 | 172 | # Shipping, before Docker 173 | 174 | * Ship packages: deb, rpm, gem, jar, homebrew... 175 | * Dependency hell. 176 | * "Works on my machine." 177 | * Base deployment often done from scratch (debootstrap...) and unreliable. 178 | 179 | 180 | # Shipping, after Docker 181 | 182 | * Ship container images with all their dependencies. 183 | * Images are bigger, but they are broken down into layers. 184 | * Only ship layers that have changed. 185 | * Save disk, network, memory usage. 186 | 187 | 188 | # Example 189 | 190 | Layers: 191 | 192 | * CentOS 193 | * JRE 194 | * Tomcat 195 | * Dependencies 196 | * Application JAR 197 | * Configuration 198 | 199 | 200 | # Devs vs Ops, before Docker 201 | 202 | * Drop a tarball (or a commit hash) with instructions. 203 | * Dev environment very different from production. 204 | * Ops don't always have a dev environment themselves ... 205 | * ... and when they do, it can differ from the devs'. 206 | * Ops have to sort out differences and make it work ... 207 | * ... or bounce it back to devs. 208 | * Shipping code causes frictions and delays. 209 | 210 | 211 | # Devs vs Ops, after Docker 212 | 213 | * Drop a container image or a Compose file. 214 | * Ops can always run that container image. 215 | * Ops can always run that Compose file. 216 | * Ops still have to adapt to prod environment, 217 | but at least they have a reference point. 218 | * Ops have tools allowing to use the same image 219 | in dev and prod. 220 | * Devs can be empowered to make releases themselves 221 | more easily. 222 | 223 | 224 | # Clean separation of concerns 225 | 226 | ![sepcon](sepcon.png) 227 | 228 | 229 | 230 | # History of containers ... and Docker 231 | 232 | 233 | # First experimentations 234 | 235 | * [IBM VM/370 (1972)](https://en.wikipedia.org/wiki/VM_(operating_system)) 236 | * [Linux VServers (2001)](http://www.solucorp.qc.ca/changes.hc?projet=vserver) 237 | * [Solaris Containers (2004)](https://en.wikipedia.org/wiki/Solaris_Containers) 238 | * [FreeBSD jails (1999)](https://www.freebsd.org/cgi/man.cgi?query=jail&sektion=8&manpath=FreeBSD+4.0-RELEASE) 239 | 240 | Containers have been around for a *very long time* indeed. 241 | 242 | 243 | 244 | # VPS-olithic period (until 2007-2008) 245 | 246 | 247 | # Containers = cheaper than VMs 248 | 249 | ![lightcont](lightcont.png) 250 | 251 | * Users: hosting providers. 252 | * Highly specialized audience with strong ops culture. 253 | 254 | 255 | # PaaS-olithic period (2008-2013) 256 | 257 | 258 | # Containers = easier than VMs 259 | 260 | ![heroku 2007](heroku-first-homepage.png) 261 | 262 | * I can't speak for Heroku, but containers were (one of) dotCloud's secret weapon 263 | 264 | 265 | # The origins of the Docker Project 266 | 267 | * dotCloud was operating a PaaS, using a custom container engine. 268 | * This engine was based on OpenVZ (and later, LXC) and AUFS. 269 | * It started (circa 2008) as a single Python script. 270 | * By 2012, the engine had multiple (~10) Python components. 271 |
(and ~100 other micro-services!) 272 | * End of 2012, dotCloud refactors this container engine. 273 | * The codename for this project is "Docker." 274 | 275 | 276 | # First public release 277 | 278 | * March 2013, PyCon, Santa Clara: 279 |
"Docker" is shown to a public audience for the first time. 280 | * It is released with an open source license. 281 | * Very positive reactions and feedback! 282 | * The dotCloud team progressively shifts to Docker development. 283 | * The same year, dotCloud changes name to Docker. 284 | * In 2014, the PaaS activity is sold. 285 | 286 | 287 | # Docker early days (2013-2014) 288 | 289 | 290 | # First users of Docker 291 | 292 | * PAAS builders (Flynn, Dokku, Tsuru, Deis...) 293 | * PAAS users (those big enough to justify building their own) 294 | * CI platforms 295 | * developers, developers, developers, developers 296 | 297 | 298 | # Positive feedback loop 299 | 300 | * In 2013, the technology under containers (cgroups, namespaces, copy-on-write storage...) 301 | had many blind spots. 302 | * The growing popularity of Docker and containers exposed many bugs. 303 | * As a result, those bugs were fixed, resulting in better stability for containers. 304 | * Any decent hosting/cloud provider can run containers today. 305 | * Containers become a great tool to deploy/move workloads to/from on-prem/cloud. 306 | 307 | 308 | # Maturity (2015-2016) 309 | 310 | 311 | # Docker becomes an industry standard 312 | 313 | * Docker reaches the symbolic 1.0 milestone. 314 | * Existing systems like Mesos and Cloud Foundry add Docker support. 315 | * Standards like OCI, CNCF appear. 316 | * Other container engines are developed. 317 | 318 | 319 | # Docker becomes a platform 320 | 321 | * The initial container engine is now known as "Docker Engine." 322 | * Other tools are added: 323 | * Docker Compose (formerly "Fig") 324 | * Docker Machine 325 | * Docker Swarm 326 | * Kitematic 327 | * Docker Cloud (formerly "Tutum") 328 | * Docker Datacenter 329 | * etc. 330 | * Docker Inc. launches commercial offers. 331 | 332 | 333 | 334 | # Docker Inc. (the company) 335 | 336 | 337 | # About Docker Inc. 338 | 339 | * Docker Inc. used to be dotCloud Inc. 340 | * dotCloud Inc. used to be a French company. 341 | * Docker Inc. is the primary sponsor and contributor to the Docker Project: 342 | * Hires maintainers and contributors. 343 | * Provides infrastructure for the project. 344 | * Runs the Docker Hub. 345 | * HQ in San Francisco. 346 | * Backed by more than 100M in venture capital. 347 | 348 | 349 | # How does Docker Inc. make money? 350 | 351 | * SAAS 352 | * Docker Hub (per private repo) 353 | * Docker Cloud (per node) 354 | * Subscription 355 | * on-premise stack (Docker Datacenter) 356 | * DTR (Docker Trusted Registry) 357 | * UCP (Universal Control Plane) 358 | * CS (Commercially Supported Engine) 359 | * Support 360 | * Training and professional services 361 | 362 | -------------------------------------------------------------------------------- /slides/About_Docker/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # About Docker 3 | 4 | ![who](who.png) 5 | -------------------------------------------------------------------------------- /slides/About_Docker/How_Does_Docker_Work.md: -------------------------------------------------------------------------------- 1 | 2 | # How does Docker work? 3 | 4 | * Docker provides workflow and management for your applications. 5 | * Docker builds, runs and manages images and containers. 6 | * Docker is a client-server application. 7 | 8 | ![dockerworks.png](dockerworks.jpg) 9 | 10 | 11 | # Image 12 | 13 | * An image is the source for your containers. 14 | * You can launch containers from your images. 15 | * Images are "built" and can be stored and distributed via a registry 16 | like the Docker Hub. 17 | * Images are layered and versioned. 18 | 19 | 20 | # Images are layered 21 | 22 | ![image](image.png) 23 | 24 | 25 | # Layers 26 | 27 | * Each image is made up of layers. 28 | * The bottom layer is a regular Linux root file system. 29 | * When a Linux host boots, it mounts its root file system read-write ... 30 | * ... Docker however uses copy-on-write, so that this bottom layer 31 | stays read-only, and all changes go to a new layer sitting above. 32 | * The container can become an image on its own by freezing the top layer. 33 | * When that image is started, a new writable layer is added on top of 34 | the stack. 35 | 36 | 37 | # Registry 38 | 39 | * Stores images. 40 | 41 | * The registry is like git for containers. 42 | 43 | It holds all of the revisions of each container. 44 | 45 | * Docker pushes and pulls images from the registry. 46 | 47 | * The Docker Hub features a public registry. 48 | 49 | You can also run your own. 50 | 51 | 52 | # Container 53 | 54 | * Containers are launched from images. 55 | * They contain one or more running processes. 56 | * Can be started, stopped, restarted and killed. 57 | 58 | 59 | # Images versus containers? 60 | 61 | * An image is a stopped container. 62 | * You make an image by committing a container. 63 | * Images are building, containers are running. 64 | 65 | 66 | # Registry versus Docker Hub? 67 | 68 | * A registry is a place to store Docker images. 69 | 70 | * The Docker Hub is a set of services operated by Docker Inc. 71 | 72 | Those services include a registry. 73 | 74 | * If need be, you can run your own registry. 75 | 76 | *Note: the Docker Hub used to be known as `docker.io`.* 77 | 78 | 79 | # Create a Docker Hub account 80 | 81 | * Sign up on [hub.docker.com](https://hub.docker.com/). 82 | 83 | ![Docker Hub Sign up](signup.png) 84 | 85 | 86 | # Section summary 87 | 88 | We've learned: 89 | 90 | * About Docker Inc. 91 | * About Docker. 92 | * How to create an account on the Docker Hub. 93 | 94 | 95 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Create a Docker Hub account 96 | 97 | 1. Open a browser window. 98 | 99 | 2. Browse to the Docker Hub site. 100 | 101 | @@@ Sh 102 | https://hub.docker.com/ 103 | 104 | 3. Click on the ``Sign-up`` link. 105 | 106 | @@@ Sh 107 | https://hub.docker.com/account/signup/ 108 | 109 | 110 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Create a Docker Hub account 111 | 112 | 1. Create a Docker Hub account. 113 | 114 | ![signup](signup.png) 115 | 116 | 2. Verify your Docker Hub account. 117 | 118 | 3. Login to your Docker Hub account. 119 | 120 | @@@ Sh 121 | https://hub.docker.com/account/login/ 122 | 123 | 124 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Optional: Create a GitHub account 125 | 126 | 1. If you don't already have a GitHub account it'll be pretty useful later on. 127 | 128 | @@@ Sh 129 | https://github.com/join 130 | -------------------------------------------------------------------------------- /slides/About_Docker/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Docker 30,000ft overview 3 | 4 | ## Objectives 5 | 6 | In this lesson, we will learn about: 7 | 8 | * Why containers (non-technical elevator pitch) 9 | * Why containers (technical elevator pitch) 10 | * How Docker helps us to build, ship, and run 11 | * The history of containers 12 | 13 | We won't actually run Docker or containers in this chapter (yet!). 14 | 15 | Don't worry, we will get to that fast enough! 16 | -------------------------------------------------------------------------------- /slides/About_Docker/appcont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/About_Docker/appcont.png -------------------------------------------------------------------------------- /slides/About_Docker/deploysys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/About_Docker/deploysys.png -------------------------------------------------------------------------------- /slides/About_Docker/dockerworks.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/About_Docker/dockerworks.jpg -------------------------------------------------------------------------------- /slides/About_Docker/elimatrix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/About_Docker/elimatrix.png -------------------------------------------------------------------------------- /slides/About_Docker/heroku-first-homepage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/About_Docker/heroku-first-homepage.png -------------------------------------------------------------------------------- /slides/About_Docker/history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/About_Docker/history.png -------------------------------------------------------------------------------- /slides/About_Docker/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/About_Docker/image.png -------------------------------------------------------------------------------- /slides/About_Docker/layer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/About_Docker/layer.png -------------------------------------------------------------------------------- /slides/About_Docker/lightcont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/About_Docker/lightcont.png -------------------------------------------------------------------------------- /slides/About_Docker/matrix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/About_Docker/matrix.png -------------------------------------------------------------------------------- /slides/About_Docker/problem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/About_Docker/problem.png -------------------------------------------------------------------------------- /slides/About_Docker/sepcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/About_Docker/sepcon.png -------------------------------------------------------------------------------- /slides/About_Docker/shipeco.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/About_Docker/shipeco.png -------------------------------------------------------------------------------- /slides/About_Docker/shipping.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/About_Docker/shipping.png -------------------------------------------------------------------------------- /slides/About_Docker/signup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/About_Docker/signup.png -------------------------------------------------------------------------------- /slides/About_Docker/superlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/About_Docker/superlight.png -------------------------------------------------------------------------------- /slides/About_Docker/who.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/About_Docker/who.png -------------------------------------------------------------------------------- /slides/Ambassadors/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # Ambassadors 3 | 4 | We've already seen a couple of ways we can manage our application 5 | architecture in Docker. 6 | 7 | * With network aliases. 8 | * With links. 9 | 10 | We're now going to see a pattern for service portability we call: 11 | ambassadors. 12 | 13 | 14 | # Introduction to Ambassadors 15 | 16 | The ambassador pattern: 17 | 18 | * Takes advantage of Docker's per-container naming system and abstracts 19 | connections between services. 20 | * Allows you to manage services without hard-coding connection 21 | information inside applications. 22 | 23 | To do this, instead of directly connecting containers you insert 24 | ambassador containers. 25 | 26 | 27 | 28 | ![ambassador](diagram.png) 29 | 30 | 31 | # Interacting with ambassadors 32 | 33 | * The web application container uses normal Docker networking to connect 34 | to the ambassador. 35 | * The database container also talks with an ambassador. 36 | * For both containers, there is no difference between normal 37 | operation and operation with ambassador containers. 38 | * If the database container is moved (or a failover happens), its new location will 39 | be tracked by the ambassador containers, and the web application 40 | container will still be able to connect, without reconfiguration. 41 | 42 | 43 | # Ambassadors for simple service discovery 44 | 45 | Use case: 46 | 47 | * my application code connects to `redis` on the default port (6379), 48 | * my Redis service runs on another machine, on a non-default port (e.g. 12345), 49 | * I want to use an ambassador to let my application connect without modification. 50 | 51 | The ambassador will be: 52 | 53 | * a container running right next to my application, 54 | * using the name `redis` (or linked as `redis`), 55 | * listening on port 6379, 56 | * forwarding connections to the actual Redis service. 57 | 58 | 59 | # Ambassadors for service migration 60 | 61 | Use case: 62 | 63 | * my application code still connects to `redis`, 64 | * my Redis service runs somewhere else, 65 | * my Redis service is moved to a different host+port, 66 | * the location of the Redis service is given to me via e.g. DNS SRV records, 67 | * I want to use an ambassador to automatically connect to the new location, with as little disruption as possible. 68 | 69 | The ambassador will be: 70 | 71 | * the same kind of container as before, 72 | * running an additional routine to monitor DNS SRV records, 73 | * updating the forwarding destination when the DNS SRV records are updated. 74 | 75 | 76 | # Ambassadors for credentials injection 77 | 78 | Use case: 79 | 80 | * my application code still connects to `redis`, 81 | * my application code doesn't provide Redis credentials, 82 | * my production Redis service requires credentials, 83 | * my staging Redis service requires different credentials, 84 | * I want to use an ambassador to abstract those credentials. 85 | 86 | The ambassador will be: 87 | 88 | * a container using the name `redis` (or a link), 89 | * passed the credentials to use, 90 | * running a custom proxy that accepts connections on Redis default port, 91 | * performing authentication with the target Redis service before forwarding traffic. 92 | 93 | 94 | # Ambassadors for load balancing 95 | 96 | Use case: 97 | 98 | * my application code connects to a web service called `api`, 99 | * I want to run multiple instances of the `api` backend, 100 | * those instances will be on different machines and ports, 101 | * I want to use an ambassador to abstract those details. 102 | 103 | The ambassador will be: 104 | 105 | * a container using the name `api` (or a link), 106 | * passed the list of backends to use (statically or dynamically), 107 | * running a load balancer (e.g. HAProxy or NGINX), 108 | * dispatching requests across all backends transparently. 109 | 110 | 111 | # "Ambassador" is a *pattern* 112 | 113 | There are many ways to implement the pattern. 114 | 115 | Different deployments will use different underlying technologies. 116 | 117 | * On-premise deployments with a trusted network can track 118 | container locations in e.g. Zookeeper, and generate HAproxy 119 | configurations each time a location key changes. 120 | * Public cloud deployments or deployments across unsafe 121 | networks can add TLS encryption. 122 | * Ad-hoc deployments can use a master-less discovery protocol 123 | like avahi to register and discover services. 124 | * It is also possible to do one-shot reconfiguration of the 125 | ambassadors. It is slightly less dynamic but has much less 126 | requirements. 127 | * Ambassadors can be used in addition to, or instead of, overlay networks. 128 | 129 | 130 | # Section summary 131 | 132 | We've learned how to: 133 | 134 | * Understand the ambassador pattern and what it is used for (service portability). 135 | 136 | For more information about the ambassador pattern, including demos on Swarm and ECS: 137 | 138 | * AWS re:invent 2015 [DVO317](https://www.youtube.com/watch?v=7CZFpHUPqXw) 139 | * [SwarmWeek video about Swarm+Compose](https://youtube.com/watch?v=qbIvUvwa6As) 140 | 141 | -------------------------------------------------------------------------------- /slides/Ambassadors/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Ambassadors 3 | 4 | ![](ambassador.jpg) -------------------------------------------------------------------------------- /slides/Ambassadors/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Ambassadors 3 | 4 | ## Objectives 5 | 6 | At the end of this lesson, you will be able to understand the ambassador pattern. 7 | 8 | Ambassadors abstract the connection details for your services: 9 | 10 | * discovery (where is my service actually running?) 11 | * migration (what if my service has to be moved while I use it?) 12 | * fail over (what if my service has a replication system, and I need to connect to the right instance?) 13 | * load balancing (what if there are multiple instances of my service?) 14 | * authentication (what if my service requires credentials, certificates, or otherwise?) 15 | 16 | -------------------------------------------------------------------------------- /slides/Ambassadors/ambassador.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Ambassadors/ambassador.jpg -------------------------------------------------------------------------------- /slides/Ambassadors/diagram.odg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Ambassadors/diagram.odg -------------------------------------------------------------------------------- /slides/Ambassadors/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Ambassadors/diagram.png -------------------------------------------------------------------------------- /slides/Background_Containers/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # A non-interactive container 3 | 4 | We will run a small custom container. 5 | 6 | This container just displays the time every second. 7 | 8 | @@@ Sh 9 | $ docker run jpetazzo/clock 10 | Fri Feb 20 00:28:53 UTC 2015 11 | Fri Feb 20 00:28:54 UTC 2015 12 | Fri Feb 20 00:28:55 UTC 2015 13 | ... 14 | 15 | * This container will run forever. 16 | * To stop it, press `^C`. 17 | * Docker has automatically downloaded the image `jpetazzo/clock`. 18 | * This image is a user image, created by `jpetazzo`. 19 | * We will hear more about user images (and other types of images) later. 20 | 21 | 22 | # Run a container in the background 23 | 24 | Containers can be started in the background, with the `-d` flag (daemon mode): 25 | 26 | @@@ Sh 27 | $ docker run -d jpetazzo/clock 28 | 47d677dcfba4277c6cc68fcaa51f932b544cab1a187c853b7d0caf4e8debe5ad 29 | 30 | * We don't see the output of the container. 31 | * But don't worry: Docker collects that output and logs it! 32 | * Docker gives us the ID of the container. 33 | 34 | 35 | # List running containers 36 | 37 | How can we check that our container is still running? 38 | 39 | With `docker ps`, just like the UNIX `ps` command, lists running processes. 40 | 41 | @@@ Sh 42 | $ docker ps 43 | CONTAINER ID IMAGE ... CREATED STATUS ... 44 | 47d677dcfba4 jpetazzo/clock ... 2 minutes ago Up 2 minutes ... 45 | 46 | Docker tells us: 47 | 48 | * The (truncated) ID of our container. 49 | * The image used to start the container. 50 | * That our container has been running (`Up`) for a couple of minutes. 51 | * Other information (COMMAND, PORTS, NAMES) that we will explain later. 52 | 53 | 54 | # Starting more containers 55 | 56 | Let's start two more containers. 57 | 58 | @@@ Sh 59 | $ docker run -d jpetazzo/clock 60 | 57ad9bdfc06bb4407c47220cf59ce21585dce9a1298d7a67488359aeaea8ae2a 61 | $ docker run -d jpetazzo/clock 62 | 068cc994ffd0190bbe025ba74e4c0771a5d8f14734af772ddee8dc1aaf20567d 63 | 64 | Check that `docker ps` correctly reports all 3 containers. 65 | 66 | 67 | # Two useful flags for `docker ps` 68 | 69 | To see only the last container that was started: 70 | 71 | @@@ Sh 72 | $ docker ps -l 73 | CONTAINER ID IMAGE ... CREATED STATUS ... 74 | 068cc994ffd0 jpetazzo/clock ... 2 minutes ago Up 2 minutes ... 75 | 76 | To see only the ID of containers: 77 | 78 | @@@ Sh 79 | $ docker ps -q 80 | 068cc994ffd0 81 | 57ad9bdfc06b 82 | 47d677dcfba4 83 | 84 | Combine those flags to see only the ID of the last container started! 85 | 86 | @@@ Sh 87 | $ docker ps -lq 88 | 068cc994ffd0 89 | 90 | 91 | # View the logs of a container 92 | 93 | We told you that Docker was logging the container output. 94 | 95 | Let's see that now. 96 | 97 | @@@ Sh 98 | $ docker logs 068 99 | Fri Feb 20 00:39:52 UTC 2015 100 | Fri Feb 20 00:39:53 UTC 2015 101 | ... 102 | 103 | * We specified a *prefix* of the full container ID. 104 | * You can, of course, specify the full ID. 105 | * The `logs` command will output the *entire* logs of the container. 106 |
(Sometimes, that will be too much. Let's see how to address that.) 107 | 108 | 109 | # View only the tail of the logs 110 | 111 | To avoid being spammed with eleventy pages of output, 112 | we can use the `--tail` option: 113 | 114 | @@@ Sh 115 | $ docker logs --tail 3 068 116 | Fri Feb 20 00:55:35 UTC 2015 117 | Fri Feb 20 00:55:36 UTC 2015 118 | Fri Feb 20 00:55:37 UTC 2015 119 | 120 | * The parameter is the number of lines that we want to see. 121 | 122 | 123 | # Follow the logs in real time 124 | 125 | Just like with the standard UNIX command `tail -f`, we can 126 | follow the logs of our container: 127 | 128 | @@@ Sh 129 | $ docker logs --tail 1 --follow 068 130 | Fri Feb 20 00:57:12 UTC 2015 131 | Fri Feb 20 00:57:13 UTC 2015 132 | ^C 133 | 134 | * This will display the last line in the log file. 135 | * Then, it will continue to display the logs in real time. 136 | * Use `^C` to exit. 137 | 138 | 139 | # Stop our container 140 | 141 | There are two ways we can terminate our detached container. 142 | 143 | * Killing it using the `docker kill` command. 144 | * Stopping it using the `docker stop` command. 145 | 146 | The first one stops the container immediately, by using the 147 | `KILL` signal. 148 | 149 | The second one is more graceful. It sends a `TERM` signal, 150 | and after 10 seconds, if the container has not stopped, it 151 | sends `KILL.` 152 | 153 | Reminder: the `KILL` signal cannot be intercepted, and will 154 | forcibly terminate the container. 155 | 156 | 157 | # Stopping our containers 158 | 159 | Let's stop one of those containers: 160 | 161 | @@@ Sh 162 | $ docker stop 47d6 163 | 47d6 164 | 165 | This will take 10 seconds: 166 | 167 | * Docker sends the TERM signal; 168 | * the container doesn't react to this signal 169 | (it's a simple Shell script with no special 170 | signal handling); 171 | * 10 seconds later, since the container is still 172 | running, Docker sends the KILL signal; 173 | * this terminates the container. 174 | 175 | 176 | # Killing the remaining containers 177 | 178 | Let's be less patient with the two other containers: 179 | 180 | @@@ Sh 181 | $ docker kill 068 57ad 182 | 068 183 | 57ad 184 | 185 | The `stop` and `kill` commands can take multiple container IDs. 186 | 187 | Those containers will be terminated immediately (without 188 | the 10 seconds delay). 189 | 190 | Let's check that our containers don't show up anymore: 191 | 192 | @@@ Sh 193 | $ docker ps 194 | 195 | 196 | # List stopped containers 197 | 198 | We can also see stopped containers, with the `-a` (`--all`) option. 199 | 200 | @@@ Sh 201 | $ docker ps -a 202 | CONTAINER ID IMAGE ... CREATED STATUS 203 | 068cc994ffd0 jpetazzo/clock ... 21 min. ago Exited (137) 3 min. ago 204 | 57ad9bdfc06b jpetazzo/clock ... 21 min. ago Exited (137) 3 min. ago 205 | 47d677dcfba4 jpetazzo/clock ... 23 min. ago Exited (137) 3 min. ago 206 | 5c1dfd4d81f1 jpetazzo/clock ... 40 min. ago Exited (0) 40 min. ago 207 | b13c164401fb ubuntu ... 55 min. ago Exited (130) 53 min. ago 208 | -------------------------------------------------------------------------------- /slides/Background_Containers/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Background Containers 3 | 4 | ![Background Containers](background-containers.jpg) 5 | -------------------------------------------------------------------------------- /slides/Background_Containers/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Background Containers 3 | 4 | ## Objectives 5 | 6 | Our first containers were *interactive*. 7 | 8 | We will now see how to: 9 | 10 | * Run a non-interactive container. 11 | * Run a container in the background. 12 | * List running containers. 13 | * Check the logs of a container. 14 | * Stop a container. 15 | * List stopped containers. -------------------------------------------------------------------------------- /slides/Background_Containers/background-containers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Background_Containers/background-containers.jpg -------------------------------------------------------------------------------- /slides/Building_Images_Interactively/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # Building Images Interactively 3 | 4 | As we have seen, the images on the Docker Hub are sometimes very basic. 5 | 6 | How do we want to construct our own images? 7 | 8 | As an example, we will build an image that has `figlet`. 9 | 10 | First, we will do it manually with `docker commit`. 11 | 12 | Then, in an upcoming chapter, we will use a `Dockerfile` and `docker build`. 13 | 14 | 15 | # Building from a base 16 | 17 | Our base will be the `ubuntu` image. 18 | 19 | 20 | # Create a new container and make some changes 21 | 22 | Start an Ubuntu container: 23 | 24 | @@@ Sh 25 | $ docker run -it ubuntu 26 | root@:#/ 27 | 28 | Run the command `apt-get update` to refresh the list of packages available to install. 29 | 30 | Then run the command `apt-get install figlet` to install the program we are interested in. 31 | 32 | @@@ Sh 33 | root@:#/ apt-get update && apt-get install figlet 34 | .... OUTPUT OF APT-GET COMMANDS .... 35 | 36 | 37 | # Inspect the changes 38 | 39 | Type ``exit`` at the container prompt to leave the interactive session. 40 | 41 | Now let's run `docker diff` to see the difference between the base image 42 | and our container. 43 | 44 | @@@ Sh 45 | $ docker diff 46 | C /root 47 | A /root/.bash_history 48 | C /tmp 49 | C /usr 50 | C /usr/bin 51 | A /usr/bin/figlet 52 | ... 53 | 54 | 55 | # Docker tracks filesystem changes 56 | 57 | As explained before: 58 | 59 | * An image is read-only. 60 | * When we make changes, they happen in a copy of the image. 61 | * Docker can show the difference between the image, and its copy. 62 | * For performance, Docker uses copy-on-write systems. 63 |
(i.e. starting a container based on a big image 64 | doesn't incur a huge copy.) 65 | 66 | 67 | # Commit and run your image 68 | 69 | The `docker commit` command will create a new layer with those changes, 70 | and a new image using this new layer. 71 | 72 | @@@ Sh 73 | $ docker commit 74 | 75 | 76 | The output of the ``docker commit`` command will be the ID for your newly created image. 77 | 78 | We can run this image: 79 | 80 | @@@ Sh 81 | $ docker run -it 82 | root@fcfb62f0bfde:/# figlet hello 83 | _ _ _ 84 | | |__ ___| | | ___ 85 | | '_ \ / _ \ | |/ _ \ 86 | | | | | __/ | | (_) | 87 | |_| |_|\___|_|_|\___/ 88 | 89 | 90 | 91 | # Tagging images 92 | 93 | Referring to an image by its ID is not convenient. Let's tag it instead. 94 | 95 | We can use the `tag` command: 96 | 97 | @@@ Sh 98 | $ docker tag figlet 99 | 100 | But we can also specify the tag as an extra argument to `commit`: 101 | 102 | @@@ Sh 103 | $ docker commit figlet 104 | 105 | And then run it using its tag: 106 | 107 | @@@ Sh 108 | $ docker run -it figlet 109 | 110 | 111 | # What's next? 112 | 113 | Manual process = bad. 114 | 115 | Automated process = good. 116 | 117 | In the next chapter, we will learn how to automate the build 118 | process by writing a `Dockerfile`. 119 | -------------------------------------------------------------------------------- /slides/Building_Images_Interactively/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Building Images Interactively 3 | 4 | ![cmatrix](cmatrix.png) 5 | -------------------------------------------------------------------------------- /slides/Building_Images_Interactively/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Building Images Interactively 3 | 4 | ## Objectives 5 | 6 | In this lesson, we will create our first container image. 7 | 8 | It will be a basic distribution image, but we will pre-install 9 | the package `figlet`. 10 | 11 | We will: 12 | 13 | * Create a container from a base image. 14 | * Install software manually in the container, and turn it 15 | into a new image. 16 | * Learn about new commands: `docker commit`, `docker tag`, and `docker diff`. 17 | -------------------------------------------------------------------------------- /slides/Building_Images_Interactively/cmatrix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Building_Images_Interactively/cmatrix.png -------------------------------------------------------------------------------- /slides/Building_Images_With_Dockerfiles/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # `Dockerfile` overview 3 | 4 | * A `Dockerfile` is a build recipe for a Docker image. 5 | * It contains a series of instructions telling Docker how an image is constructed. 6 | * The `docker build` command builds an image from a ``Dockerfile``. 7 | 8 | 9 | # Writing our first `Dockerfile` 10 | 11 | Our Dockerfile must be in a **new, empty directory**. 12 | 13 | 1. Create a directory to hold our ``Dockerfile``. 14 | 15 | @@@ Sh 16 | $ mkdir myimage 17 | 18 | 2. Create a ``Dockerfile`` inside this directory. 19 | 20 | @@@ Sh 21 | $ cd myimage 22 | $ vim Dockerfile 23 | 24 | Of course, you can use any other editor of your choice. 25 | 26 | 27 | # Type this into our Dockerfile... 28 | 29 | @@@ docker 30 | FROM ubuntu 31 | RUN apt-get update 32 | RUN apt-get install figlet 33 | 34 | * `FROM` indicates the base image for our build. 35 | * Each `RUN` line will be executed by Docker during the build. 36 | * Our `RUN` commands **must be non-interactive.** 37 |
(No input can be provided to Docker during the build.) 38 | * In many cases, we will add the `-y` flag to `apt-get`. 39 | 40 | 41 | # Build it! 42 | 43 | Save our file, then execute: 44 | 45 | @@@ Sh 46 | $ docker build -t figlet . 47 | 48 | * `-t` indicates the tag to apply to the image. 49 | * `.` indicates the location of the *build context*. 50 |
(We will talk more about the build context later; 51 | but to keep things simple: this is the directory where 52 | our Dockerfile is located.) 53 | 54 | 55 | # What happens when we build the image? 56 | 57 | The output of `docker build` looks like this: 58 | 59 | @@@ Sh 60 | $ docker build -t figlet . 61 | Sending build context to Docker daemon 2.048 kB 62 | Sending build context to Docker daemon 63 | Step 0 : FROM ubuntu 64 | ---> e54ca5efa2e9 65 | Step 1 : RUN apt-get update 66 | ---> Running in 840cb3533193 67 | ---> 7257c37726a1 68 | Removing intermediate container 840cb3533193 69 | Step 2 : RUN apt-get install figlet 70 | ---> Running in 2b44df762a2f 71 | ---> f9e8f1642759 72 | Removing intermediate container 2b44df762a2f 73 | Successfully built f9e8f1642759 74 | 75 | * The output of the `RUN` commands has been omitted. 76 | * Let's explain what this output means. 77 | 78 | 79 | # Sending the build context to Docker 80 | 81 | @@@ Sh 82 | Sending build context to Docker daemon 2.048 kB 83 | 84 | * The build context is the `.` directory given to `docker build`. 85 | * It is sent (as an archive) by the Docker client to the Docker daemon. 86 | * This allows to use a remote machine to build using local files. 87 | * Be careful (or patient) if that directory is big and your link is slow. 88 | 89 | 90 | # Executing each step 91 | 92 | @@@ Sh 93 | Step 1 : RUN apt-get update 94 | ---> Running in 840cb3533193 95 | (...output of the RUN command...) 96 | ---> 7257c37726a1 97 | Removing intermediate container 840cb3533193 98 | 99 | * A container (`840cb3533193`) is created from the base image. 100 | * The `RUN` command is executed in this container. 101 | * The container is committed into an image (`7257c37726a1`). 102 | * The build container (`840cb3533193`) is removed. 103 | * The output of this step will be the base image for the next one. 104 | 105 | 106 | # The caching system 107 | 108 | If you run the same build again, it will be instantaneous. 109 | 110 | Why? 111 | 112 | * After each build step, Docker takes a snapshot of the resulting image. 113 | * Before executing a step, Docker checks if it has already built the 114 | same sequence. 115 | * Docker uses the exact strings defined in your Dockerfile, so: 116 | 117 | * `RUN apt-get install figlet cowsay ` 118 |
is different from 119 |
`RUN apt-get install cowsay figlet` 120 | * `RUN apt-get update` is not re-executed when the mirrors are updated 121 | 122 | You can force a rebuild with `docker build --no-cache ...`. 123 | 124 | 125 | # Running the image 126 | 127 | The resulting image is not different from the one produced manually. 128 | 129 | @@@ Sh 130 | $ docker run -ti figlet 131 | root@91f3c974c9a1:/# figlet hello 132 | _ _ _ 133 | | |__ ___| | | ___ 134 | | '_ \ / _ \ | |/ _ \ 135 | | | | | __/ | | (_) | 136 | |_| |_|\___|_|_|\___/ 137 | 138 | 139 | * Sweet is the taste of success! 140 | 141 | 142 | # Using image and viewing history 143 | 144 | The `history` command lists all the layers composing an image. 145 | 146 | For each layer, it shows its creation time, size, and creation command. 147 | 148 | When an image was built with a Dockerfile, each layer corresponds to 149 | a line of the Dockerfile. 150 | 151 | @@@ Sh 152 | $ docker history figlet 153 | IMAGE CREATED CREATED BY SIZE 154 | f9e8f1642759 About an hour ago /bin/sh -c apt-get install fi 1.627 MB 155 | 7257c37726a1 About an hour ago /bin/sh -c apt-get update 21.58 MB 156 | 07c86167cdc4 4 days ago /bin/sh -c #(nop) CMD ["/bin 0 B 157 | 4 days ago /bin/sh -c sed -i 's/^#\s*\( 1.895 kB 158 | 4 days ago /bin/sh -c echo '#!/bin/sh' 194.5 kB 159 | 4 days ago /bin/sh -c #(nop) ADD file:b 187.8 MB 160 | 161 | 162 | 163 | # Introducing JSON syntax 164 | 165 | Most Dockerfile arguments can be passed in two forms: 166 | 167 | * plain string: 168 |
`RUN apt-get install figlet` 169 | * JSON list: 170 |
`RUN ["apt-get", "install", "figlet"]` 171 | 172 | Let's change our Dockerfile as follows! 173 | 174 | @@@ Dockerfile 175 | FROM ubuntu 176 | RUN apt-get update 177 | RUN ["apt-get", "install", "figlet"] 178 | 179 | Then build the new Dockerfile. 180 | 181 | @@@ Sh 182 | $ docker build -t figlet . 183 | 184 | 185 | # JSON syntax vs string syntax 186 | 187 | Compare the new history: 188 | 189 | @@@ Sh 190 | $ docker history figlet 191 | IMAGE CREATED CREATED BY SIZE 192 | 27954bb5faaf 10 seconds ago apt-get install figlet 1.627 MB 193 | 7257c37726a1 About an hour ago /bin/sh -c apt-get update 21.58 MB 194 | 07c86167cdc4 4 days ago /bin/sh -c #(nop) CMD ["/bin 0 B 195 | 4 days ago /bin/sh -c sed -i 's/^#\s*\( 1.895 kB 196 | 4 days ago /bin/sh -c echo '#!/bin/sh' 194.5 kB 197 | 4 days ago /bin/sh -c #(nop) ADD file:b 187.8 MB 198 | 199 | * JSON syntax specifies an *exact* command to execute. 200 | * String syntax specifies a command to be wrapped within `/bin/sh -c "..."`. 201 | 202 | -------------------------------------------------------------------------------- /slides/Building_Images_With_Dockerfiles/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Building Docker images 3 | 4 | ![construction](construction.jpg) 5 | -------------------------------------------------------------------------------- /slides/Building_Images_With_Dockerfiles/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Building Images With A Dockerfile 3 | 4 | ## Objectives 5 | 6 | We will build a container image automatically, with a `Dockerfile`. 7 | 8 | At the end of this lesson, you will be able to: 9 | 10 | * Write a `Dockerfile`. 11 | * Build an image from a `Dockerfile`. 12 | -------------------------------------------------------------------------------- /slides/Building_Images_With_Dockerfiles/construction.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Building_Images_With_Dockerfiles/construction.jpg -------------------------------------------------------------------------------- /slides/Building_Images_With_Dockerfiles/webapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Building_Images_With_Dockerfiles/webapp.png -------------------------------------------------------------------------------- /slides/Cmd_And_Entrypoint/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # Defining a default command 3 | 4 | When people run our container, we want to greet them with a nice hello message, and using a custom font. 5 | 6 | For that, we will execute: 7 | 8 | @@@ Sh 9 | figlet -f script hello 10 | 11 | * `-f script` tells figlet to use a fancy font. 12 | * `hello` is the message that we want it to display. 13 | 14 | 15 | # Adding `CMD` to our Dockerfile 16 | 17 | Our new Dockerfile will look like this: 18 | 19 | @@@ docker 20 | FROM ubuntu 21 | RUN apt-get update 22 | RUN ["apt-get", "install", "figlet"] 23 | CMD figlet -f script hello 24 | 25 | * `CMD` defines a default command to run when none is given. 26 | * It can appear at any point in the file. 27 | * Each `CMD` will replace and override the previous one. 28 | * As a result, while you can have multiple `CMD` lines, it is useless. 29 | 30 | 31 | # Build and test our image 32 | 33 | Let's build it: 34 | 35 | @@@ Sh 36 | $ docker build -t figlet . 37 | ... 38 | Successfully built 042dff3b4a8d 39 | 40 | And run it: 41 | 42 | @@@ Sh 43 | $ docker run figlet 44 | _ _ _ 45 | | | | | | | 46 | | | _ | | | | __ 47 | |/ \ |/ |/ |/ / \_ 48 | | |_/|__/|__/|__/\__/ 49 | 50 | 51 | 52 | # Overriding `CMD` 53 | 54 | If we want to get a shell into our container (instead of running 55 | `figlet`), we just have to specify a different program to run: 56 | 57 | @@@ Sh 58 | $ docker run -it figlet bash 59 | root@7ac86a641116:/# 60 | 61 | * We specified `bash`. 62 | * It replaced the value of `CMD`. 63 | 64 | 65 | # Using `ENTRYPOINT` 66 | 67 | We want to be able to specify a different message on the command line, 68 | while retaining `figlet` and some default parameters. 69 | 70 | In other words, we would like to be able to do this: 71 | 72 | @@@ Sh 73 | $ docker run figlet salut 74 | _ 75 | | | 76 | , __, | | _|_ 77 | / \_/ | |/ | | | 78 | \/ \_/|_/|__/ \_/|_/|_/ 79 | 80 | 81 | We will use the `ENTRYPOINT` verb in Dockerfile. 82 | 83 | 84 | 85 | # Adding `ENTRYPOINT` to our Dockerfile 86 | 87 | Our new Dockerfile will look like this: 88 | 89 | @@@ docker 90 | FROM ubuntu 91 | RUN apt-get update 92 | RUN ["apt-get", "install", "figlet"] 93 | ENTRYPOINT ["figlet", "-f", "script"] 94 | 95 | * `ENTRYPOINT` defines a base command (and its parameters) for the container. 96 | * The command line arguments are appended to those parameters. 97 | * Like `CMD`, `ENTRYPOINT` can appear anywhere, and replaces the previous value. 98 | 99 | Why did we use JSON syntax for our `ENTRYPOINT`? 100 | 101 | 102 | # Implications of JSON vs string syntax 103 | 104 | * When CMD or ENTRYPOINT use string syntax, they get wrapped in `sh -c`. 105 | * To avoid this wrapping, you must use JSON syntax. 106 | 107 | What if we used `ENTRYPOINT` with string syntax? 108 | 109 | @@@ Sh 110 | $ docker run figlet salut 111 | 112 | This would run the following command in the `figlet` image: 113 | 114 | @@@ Sh 115 | sh -c "figlet -f script" salut 116 | 117 | 118 | # Build and test our image 119 | 120 | Let's build it: 121 | 122 | @@@ Sh 123 | $ docker build -t figlet . 124 | ... 125 | Successfully built 36f588918d73 126 | 127 | And run it: 128 | 129 | @@@ Sh 130 | $ docker run figlet salut 131 | _ 132 | | | 133 | , __, | | _|_ 134 | / \_/ | |/ | | | 135 | \/ \_/|_/|__/ \_/|_/|_/ 136 | 137 | Great success! 138 | 139 | 140 | # Using `CMD` and `ENTRYPOINT` together 141 | 142 | What if we want to define a default message for our container? 143 | 144 | Then we will use `ENTRYPOINT` and `CMD` together. 145 | 146 | * `ENTRYPOINT` will define the base command for our container. 147 | * `CMD` will define the default parameter(s) for this command. 148 | * They *both* have to use JSON syntax. 149 | 150 | 151 | # `CMD` and `ENTRYPOINT` together 152 | 153 | Our new Dockerfile will look like this: 154 | 155 | @@@ docker 156 | FROM ubuntu 157 | RUN apt-get update 158 | RUN ["apt-get", "install", "figlet"] 159 | ENTRYPOINT ["figlet", "-f", "script"] 160 | CMD ["hello world"] 161 | 162 | * `ENTRYPOINT` defines a base command (and its parameters) for the container. 163 | * If we don't specify extra command-line arguments when starting the container, 164 | the value of `CMD` is appended. 165 | * Otherwise, our extra command-line arguments are used instead of `CMD`. 166 | 167 | 168 | # Build and test our image 169 | 170 | Let's build it: 171 | 172 | @@@ Sh 173 | $ docker build -t figlet . 174 | ... 175 | Successfully built 6e0b6a048a07 176 | 177 | And run it: 178 | 179 | @@@ Sh 180 | $ docker run figlet 181 | _ _ _ _ 182 | | | | | | | | | | 183 | | | _ | | | | __ __ ,_ | | __| 184 | |/ \ |/ |/ |/ / \_ | | |_/ \_/ | |/ / | 185 | | |_/|__/|__/|__/\__/ \/ \/ \__/ |_/|__/\_/|_/ 186 | 187 | $ docker run figlet hola mundo 188 | _ _ 189 | | | | | | 190 | | | __ | | __, _ _ _ _ _ __| __ 191 | |/ \ / \_|/ / | / |/ |/ | | | / |/ | / | / \_ 192 | | |_/\__/ |__/\_/|_/ | | |_/ \_/|_/ | |_/\_/|_/\__/ 193 | 194 | 195 | 196 | # Overriding `ENTRYPOINT` 197 | 198 | What if we want to run a shell in our container? 199 | 200 | We cannot just do `docker run figlet bash` because 201 | that would just tell figlet to display the word "bash." 202 | 203 | We use the `--entrypoint` parameter: 204 | 205 | @@@ Sh 206 | $ docker run -it --entrypoint bash figlet 207 | root@6027e44e2955:/# 208 | 209 | -------------------------------------------------------------------------------- /slides/Cmd_And_Entrypoint/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # CMD and ENTRYPOINT 3 | 4 | ![Container entry doors](entrypoint.jpg) 5 | -------------------------------------------------------------------------------- /slides/Cmd_And_Entrypoint/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: CMD and ENTRYPOINT 3 | 4 | ## Objectives 5 | 6 | In this lesson, we will learn about two important 7 | Dockerfile commands: 8 | 9 | `CMD` and `ENTRYPOINT`. 10 | 11 | Those commands allow us to set the default command 12 | to run in a container. -------------------------------------------------------------------------------- /slides/Cmd_And_Entrypoint/entrypoint.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Cmd_And_Entrypoint/entrypoint.jpg -------------------------------------------------------------------------------- /slides/Cmd_And_Entrypoint/webapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Cmd_And_Entrypoint/webapp.png -------------------------------------------------------------------------------- /slides/Compose_For_Dev_Stacks/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # What is Docker Compose? 3 | 4 | Docker Compose (formerly known as fig) is an external tool. It is optional (you do not 5 | need Compose to run Docker and containers) but we recommend it highly! 6 | 7 | The general idea of Compose is to enable a very simple, powerful onboarding workflow: 8 | 9 | 1. Clone your code. 10 | 2. Run `docker-compose up`. 11 | 3. Your app is up and running! 12 | 13 | 14 | # Compose overview 15 | 16 | This is how you work with Compose: 17 | 18 | * You describe a set (or stack) of containers in a YAML file called `docker-compose.yml`. 19 | * You run `docker-compose up`. 20 | * Compose automatically pulls images, builds containers, and starts them. 21 | * Compose can set up links, volumes, and other Docker options for you. 22 | * Compose can run the containers in the background, or in the foreground. 23 | * When containers are running in the foreground, their aggregated output is shown. 24 | 25 | Before diving in, let's see a small example of Compose in action. 26 | 27 | 28 | # Compose in action 29 | 30 | ![composeup](composeup.gif) 31 | 32 | 33 | # Checking if Compose is installed 34 | 35 | If you are using the official training virtual machines, Compose has been 36 | pre-installed. 37 | 38 | You can always check that it is installed by running: 39 | 40 | @@@ Sh 41 | $ docker-compose --version 42 | 43 | 44 | # Installing Compose 45 | 46 | If you want to install Compose on your machine, there are (at least) two methods. 47 | 48 | Compose is written in Python. If you have `pip` and use it to manage other Python 49 | packages, you can install compose with: 50 | 51 | @@@ Sh 52 | $ sudo pip install docker-compose 53 | 54 | (Note: if you are familiar with `virtualenv`, you can also use it to install Compose.) 55 | 56 | If you do not have `pip`, or do not want to use it to install Compose, you can 57 | also retrieve an all-in-one binary file: 58 | 59 | @@@ Sh 60 | $ curl -L \ 61 | https://github.com/docker/compose/releases/download/1.8.0/docker-compose-`uname -s`-`uname -m` \ 62 | > /usr/local/bin/docker-compose 63 | $ chmod +x /usr/local/bin/docker-compose 64 | 65 | 66 | # Launching Our First Stack with Compose 67 | 68 | First step: clone the source code for the app we will be working on. 69 | 70 | @@@ Sh 71 | $ cd 72 | $ git clone git://github.com/jpetazzo/trainingwheels 73 | ... 74 | $ cd trainingwheels 75 | 76 | 77 | Second step: start your app. 78 | 79 | @@@ Sh 80 | $ docker-compose up 81 | 82 | Watch Compose build and run your app with the correct parameters, 83 | including linking the relevant containers together. 84 | 85 | 86 | # Launching Our First Stack with Compose 87 | 88 | Verify that the app is running at `http://:8000`. 89 | 90 | ![composeapp](composeapp.png) 91 | 92 | 93 | # Stopping the app 94 | 95 | When you hit `^C`, Compose tries to gracefully terminate all of the containers. 96 | 97 | After ten seconds (or if you press `^C` again) it will forcibly kill 98 | them. 99 | 100 | 101 | # The `docker-compose.yml` file 102 | 103 | Here is the file used in the demo: 104 | 105 | @@@ YAML 106 | version: "2" 107 | 108 | services: 109 | www: 110 | build: www 111 | ports: 112 | - 8000:5000 113 | user: nobody 114 | environment: 115 | DEBUG: 1 116 | command: python counter.py 117 | volumes: 118 | - ./www:/src 119 | 120 | redis: 121 | image: redis 122 | 123 | 124 | # Compose file versions 125 | 126 | Version 1 directly has the various containers (`www`, `redis`...) at the top level of the file. 127 | 128 | Version 2 has multiple sections: 129 | 130 | * `version` is mandatory and should be `"2"`. 131 | * `services` is mandatory and corresponds to the content of the version 1 format. 132 | * `networks` is optional and can define multiple networks on which containers can be placed. 133 | * `volumes` is optional and can define volumes to be used (and potentially shared) by the containers. 134 | 135 | 136 | # Containers in `docker-compose.yml` 137 | 138 | Each service in the YAML file must contain either `build`, or `image`. 139 | 140 | * `build` indicates a path containing a Dockerfile. 141 | * `image` indicates an image name (local, or on a registry). 142 | 143 | The other parameters are optional. 144 | 145 | They encode the parameters that you would typically add to `docker run`. 146 | 147 | Sometimes they have several minor improvements. 148 | 149 | 150 | # Container parameters 151 | 152 | * `command` indicates what to run (like `CMD` in a Dockerfile). 153 | * `ports` translates to one (or multiple) `-p` options to map ports. 154 |
You can specify local ports (i.e. `x:y` to expose public port `x`). 155 | * `volumes` translates to one (or multiple) `-v` options. 156 |
You can use relative paths here. 157 | 158 | For the full list, check http://docs.docker.com/compose/yml/. 159 | 160 | 161 | # Compose commands 162 | 163 | We already saw `docker-compose up`, but another one is `docker-compose build`. 164 | It will execute `docker build` for all containers mentioning a `build` path. 165 | 166 | It is common to execute the build and run steps in sequence: 167 | 168 | @@@ Sh 169 | docker-compose build && docker-compose up 170 | 171 | Another common option is to start containers in the background: 172 | 173 | @@@ Sh 174 | docker-compose up -d 175 | 176 | 177 | # Check container status 178 | 179 | It can be tedious to check the status of your containers with `docker ps`, 180 | especially when running multiple apps at the same time. 181 | 182 | Compose makes it easier; with `docker-compose ps` you will see only the status of the 183 | containers of the current stack: 184 | 185 | 186 | @@@ Sh 187 | $ docker-compose ps 188 | Name Command State Ports 189 | ---------------------------------------------------------------------------- 190 | trainingwheels_redis_1 /entrypoint.sh red Up 6379/tcp 191 | trainingwheels_www_1 python counter.py Up 0.0.0.0:8000->5000/tcp 192 | 193 | 194 | 195 | # Cleaning up 196 | 197 | If you have started your application in the background with Compose and 198 | want to stop it easily, you can use the `kill` command: 199 | 200 | @@@ Sh 201 | $ docker-compose kill 202 | 203 | Likewise, `docker-compose rm` will let you remove containers (after confirmation): 204 | 205 | @@@ Sh 206 | $ docker-compose rm 207 | Going to remove trainingwheels_redis_1, trainingwheels_www_1 208 | Are you sure? [yN] y 209 | Removing trainingwheels_redis_1... 210 | Removing trainingwheels_www_1... 211 | 212 | Alternatively, `docker-compose down` will stop and remove containers. 213 | 214 | @@@ Sh 215 | $ docker-compose down 216 | Stopping trainingwheels_www_1 ... done 217 | Stopping trainingwheels_redis_1 ... done 218 | Removing trainingwheels_www_1 ... done 219 | Removing trainingwheels_redis_1 ... done 220 | 221 | 222 | 223 | # Special handling of volumes 224 | 225 | Compose is smart. If your container uses volumes, when you restart your 226 | application, Compose will create a new container, but carefully re-use 227 | the volumes it was using previously. 228 | 229 | This makes it easy to upgrade a stateful service, by pulling its 230 | new image and just restarting your stack with Compose. 231 | 232 | 233 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Installing compose 234 | 235 | To install `docker-compose`: 236 | 237 | @@@ Sh 238 | curl -L \ 239 | https://github.com/docker/compose/releases/download/1.2.0/docker-compose-`uname -s`-`uname -m` \ 240 | > /usr/local/bin/docker-compose 241 | chmod +x /usr/local/bin/docker-compose 242 | 243 | You can also use `pip` if you prefer: 244 | 245 | @@@ Sh 246 | sudo pip install -U docker-compose 247 | 248 | 249 | 250 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Clone repo 251 | Clone the source code for the app we will be working on. 252 | 253 | @@@ Sh 254 | cd 255 | git clone https://github.com/docker-training/simplefig 256 | cd simplefig 257 | 258 | 259 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Dockerfile 260 | Create this Dockerfile: 261 | 262 | @@@ docker 263 | FROM python:2.7 264 | ADD requirements.txt /code/requirements.txt 265 | WORKDIR /code 266 | RUN pip install -r requirements.txt 267 | ADD . /code 268 | 269 | 270 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: docker-compose.yml 271 | Now create a `docker-compose.yml` to store the runtime properties of the app. 272 | 273 |
web:
274 |   build: .
275 |   command: python app.py
276 |   ports:
277 |    - "5000:5000"
278 |   volumes:
279 |    - .:/code
280 |   links:
281 |    - redis
282 | redis:
283 |   image: orchardup/redis
284 | 
285 | 286 | 287 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Docker-Compose up 288 | Run `docker-compose up` in the directory, and watch compose build and run your app with 289 | the correct parameters, including linking the relevant containers together. 290 | 291 | @@@ Sh 292 | docker-compose up 293 | 294 | 295 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Verify app is running 296 | Verify that the app is running at `http://:5000`. 297 | 298 | ![composeapp](composeapp.png) 299 | 300 | 301 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Additional commands 302 | `docker-compose` introduces a unit of abstraction called a "service" (mostly, a container 303 | that interacts with other containers in some way and has specific runtime 304 | properties). 305 | 306 | To rebuild all the services in your `docker-compose.yml`: 307 | 308 | @@@ Sh 309 | docker-compose build 310 | 311 | To run `docker-compose up` in the background instead of the foreground: 312 | 313 | @@@ Sh 314 | docker-compose up -d 315 | 316 | To see currently running services: 317 | 318 | @@@ Sh 319 | docker-compose ps 320 | 321 | To remove the existing services: 322 | 323 | @@@ Sh 324 | docker-compose rm 325 | 326 | -------------------------------------------------------------------------------- /slides/Compose_For_Dev_Stacks/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Compose For Development Stacks 3 | 4 | ![Compose](fig.png) 5 | -------------------------------------------------------------------------------- /slides/Compose_For_Dev_Stacks/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Using Docker Compose for Development Stacks 3 | 4 | ## Objectives 5 | 6 | Dockerfiles are great to build a single container. 7 | 8 | But when you want to start a complex stack made of multiple containers, 9 | you need a different tool. This tool is Docker Compose. 10 | 11 | In this lesson, you will use Compose to bootstrap a development environment. 12 | -------------------------------------------------------------------------------- /slides/Compose_For_Dev_Stacks/composeapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Compose_For_Dev_Stacks/composeapp.png -------------------------------------------------------------------------------- /slides/Compose_For_Dev_Stacks/composeup.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Compose_For_Dev_Stacks/composeup.gif -------------------------------------------------------------------------------- /slides/Compose_For_Dev_Stacks/fig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Compose_For_Dev_Stacks/fig.png -------------------------------------------------------------------------------- /slides/Connecting_Containers_With_Links/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # How *links* work 3 | 4 | * Links are created *between two containers* 5 | * Links are created *from the client to the server* 6 | * Links associate an arbitrary name to an existing container 7 | * Links exist *only in the context of the client* 8 | 9 | 10 | # The plan 11 | 12 | * We will create the `redis` container first. 13 | * Then, we will create the `www` container, *with a link to the previous container.* 14 | * We don't need to use a custom network for this to work. 15 | 16 | 17 | # Create the `redis` container 18 | 19 | Let's launch a container from the `redis` image. 20 | 21 | @@@ Sh 22 | $ docker run -d --name datastore redis 23 | 24 | 25 | Let's check the container is running: 26 | 27 | @@@ Sh 28 | $ docker ps -l 29 | CONTAINER ID IMAGE COMMAND ... PORTS NAMES 30 | 9efd72a4f320 redis:latest redis-server ... 6379/tcp datastore 31 | 32 | 33 | * Our container is launched and running an instance of Redis. 34 | * We used the `--name` flag to reference our container easily later. 35 | * We could have used *any name we wanted.* 36 | 37 | 38 | # Create the `www` container 39 | 40 | If we create the web container without any extra option, it will not be able to connect to redis. 41 | 42 | @@@ Sh 43 | $ docker run -dP jpetazzo/trainingwheels 44 | 45 | Check the port number with `docker ps`, and connect to it. 46 | 47 | We get the same red error page as before. 48 | 49 | 50 | # How our app connects to Redis 51 | 52 | Remember, in the code, we connect to the name `redis`: 53 | 54 | @@@ Python 55 | redis = redis.Redis("redis") 56 | 57 | * This means "try to connect to 'redis'". 58 | * Not 192.168.123.234. 59 | * Not redis.prod.mycompany.net. 60 | 61 | *Obviously* it doesn't work. 62 | 63 | 64 | # Creating a linked container 65 | 66 | Docker allows to specify *links*. 67 | 68 | Links indicate an intent: "this container will connect to this other container." 69 | 70 | Here is how to create our first link: 71 | 72 | @@@ Sh 73 | $ docker run -ti --link datastore:redis alpine sh 74 | 75 | In this container, we can communicate with `datastore` using 76 | the `redis` DNS alias. 77 | 78 | 79 | # DNS 80 | 81 | Docker has created a DNS entry for the container, resolving to its internal IP address. 82 | 83 | @@@ Sh 84 | $ docker run -it --link datastore:redis alpine ping redis 85 | PING redis (172.17.0.29): 56 data bytes 86 | 64 bytes from 172.17.0.29: icmp_seq=0 ttl=64 time=0.164 ms 87 | 64 bytes from 172.17.0.29: icmp_seq=1 ttl=64 time=0.122 ms 88 | 64 bytes from 172.17.0.29: icmp_seq=2 ttl=64 time=0.086 ms 89 | ^C--- redis ping statistics --- 90 | 3 packets transmitted, 3 packets received, 0% packet loss 91 | round-trip min/avg/max/stddev = 0.086/0.124/0.164/0.032 ms 92 | 93 | 94 | * The ``--link`` flag connects one container to another. 95 | * We specify the name of the container to link to, ``datastore``, and an 96 | alias for the link, ``redis``, in the format ``name:alias``. 97 | 98 | 99 | # Starting our application 100 | 101 | Now that we've poked around a bit let's start the application itself in 102 | a fresh container: 103 | 104 | @@@ Sh 105 | $ docker run -d -P --link datastore:redis jpetazzo/trainingwheels 106 | 107 | Now let's check the port number associated to the container. 108 | 109 | @@@ Sh 110 | $ docker ps -l 111 | 112 | 113 | # Confirming that our application works properly 114 | 115 | Finally, let's browse to our application and confirm it's working. 116 | 117 | @@@ Sh 118 | http://: 119 | 120 | 121 | # Links and environment variables 122 | 123 | In addition to the DNS information, Docker will automatically set environment variables in our container, giving extra details about the linked container. 124 | 125 | @@@ Sh 126 | $ docker run --link datastore:redis alpine env 127 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 128 | HOSTNAME=0738e57b771e 129 | REDIS_PORT=tcp://172.17.0.120:6379 130 | REDIS_PORT_6379_TCP=tcp://172.17.0.120:6379 131 | REDIS_PORT_6379_TCP_ADDR=172.17.0.120 132 | REDIS_PORT_6379_TCP_PORT=6379 133 | REDIS_PORT_6379_TCP_PROTO=tcp 134 | REDIS_NAME=/dreamy_wilson/redis 135 | REDIS_ENV_REDIS_VERSION=2.8.13 136 | REDIS_ENV_REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-2.8.13.tar.gz 137 | REDIS_ENV_REDIS_DOWNLOAD_SHA1=a72925a35849eb2d38a1ea076a3db82072d4ee43 138 | HOME=/ 139 | RUBY_MAJOR=2.1 140 | RUBY_VERSION=2.1.2 141 | 142 | 143 | * Each variables is prefixed with the link alias: ``redis``. 144 | * Includes connection information PLUS any environment variables set in 145 | the ``datastore`` container via ``ENV`` instructions. 146 | 147 | 148 | # Differences between network aliases and links 149 | 150 | * With network aliases, you can start containers in *any order.* 151 | * With links, you have to start the server (in our example: Redis) first. 152 | * With network aliases, you cannot change the name of the server once it is running. If you want to add a name, you have to create a new container. 153 | * With links, you can give new names to an existing container. 154 | * Network aliases require the use of a custom network. 155 | * Links can be used on the default bridge network. 156 | * Network aliases work across multi-host networking. 157 | * Links (as of Engine 1.11) only work with local containers (but this might be changed in the future). 158 | * Network aliases don't populate environment variables. 159 | * Links give access to the environment of the target container. 160 | 161 | 162 | # Section summary 163 | 164 | We've learned how to: 165 | 166 | * Create links between containers. 167 | * Use names and links to communicate across containers. 168 | 169 | -------------------------------------------------------------------------------- /slides/Connecting_Containers_With_Links/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Connecting Containers With Links 3 | 4 | ![graph](graph.gif) 5 | -------------------------------------------------------------------------------- /slides/Connecting_Containers_With_Links/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Connecting containers with links 3 | 4 | ## Objectives 5 | 6 | Links were the "legacy" way of connecting containers (before the implementation of the CNM). 7 | 8 | They are still useful in some scenarios. 9 | 10 | -------------------------------------------------------------------------------- /slides/Connecting_Containers_With_Links/graph.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Connecting_Containers_With_Links/graph.gif -------------------------------------------------------------------------------- /slides/Connecting_Containers_With_Links/notes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Connecting_Containers_With_Links/notes.png -------------------------------------------------------------------------------- /slides/Connecting_Containers_With_Links/redisonrails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Connecting_Containers_With_Links/redisonrails.png -------------------------------------------------------------------------------- /slides/Container_Network_Model/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # The Container Network Model 3 | 4 | ![A denser graph network](complex-network.jpg) 5 | -------------------------------------------------------------------------------- /slides/Container_Network_Model/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: The Container Network Model 3 | 4 | ## Objectives 5 | 6 | We will learn about the CNM (Container Network Model). 7 | 8 | At the end of this lesson, you will be able to: 9 | 10 | * Create a private network for a group of containers. 11 | * Use container naming to connect services together. 12 | * Dynamically connect and disconnect containers to networks. 13 | * Set the IP address of a container. 14 | 15 | We will also explain the principle of overlay networks and network plugins. 16 | -------------------------------------------------------------------------------- /slides/Container_Network_Model/complex-network.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Container_Network_Model/complex-network.jpg -------------------------------------------------------------------------------- /slides/Container_Network_Model/trainingwheels-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Container_Network_Model/trainingwheels-error.png -------------------------------------------------------------------------------- /slides/Container_Network_Model/trainingwheels-ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Container_Network_Model/trainingwheels-ok.png -------------------------------------------------------------------------------- /slides/Container_Networking_Basics/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # A simple, static web server 3 | 4 | Run the Docker Hub image `nginx`, which contains a basic web server: 5 | 6 | @@@ Sh 7 | $ docker run -d -P nginx 8 | 66b1ce719198711292c8f34f84a7b68c3876cf9f67015e752b94e189d35a204e 9 | 10 | * Docker will download the image from the Docker Hub. 11 | * `-d` tells Docker to run the image in the background. 12 | * `-P` tells Docker to make this service reachable from other computers. 13 |
(`-P` is the short version of `--publish-all`.) 14 | 15 | But, how do we connect to our web server now? 16 | 17 | 18 | # Finding our web server port 19 | 20 | We will use `docker ps`: 21 | 22 | @@@ Sh 23 | $ docker ps 24 | CONTAINER ID IMAGE ... PORTS ... 25 | e40ffb406c9e nginx ... 0.0.0.0:32769->80/tcp, 0.0.0.0:32768->443/tcp ... 26 | 27 | 28 | * The web server is running on ports 80 and 443 inside the container. 29 | * Those ports are mapped to ports 32769 and 32768 on our Docker host. 30 | 31 | We will explain the whys and hows of this port mapping. 32 | 33 | But first, let's make sure that everything works properly. 34 | 35 | 36 | # Connecting to our web server (GUI) 37 | 38 | Point your browser to the IP address of your Docker host, on the port 39 | shown by `docker ps` for container port 80. 40 | 41 | ![Screenshot](web.png) 42 | 43 | 44 | # Connecting to our web server (CLI) 45 | 46 | You can also use `curl` directly from the Docker host. 47 | 48 | Make sure to use the right port number if it is different 49 | from the example below: 50 | 51 | @@@ Sh 52 | $ curl localhost:32769 53 | 54 | 55 | 56 | Welcome to nginx! 57 | ... 58 | 59 | 60 | # Why are we mapping ports? 61 | 62 | * We are out of IPv4 addresses. 63 | * Containers cannot have public IPv4 addresses. 64 | * They have private addresses. 65 | * Services have to be exposed port by port. 66 | * Ports have to be mapped to avoid conflicts. 67 | 68 | 69 | # Finding the web server port in a script 70 | 71 | Parsing the output of `docker ps` would be painful. 72 | 73 | There is a command to help us: 74 | 75 | @@@ Sh 76 | $ docker port 80 77 | 32769 78 | 79 | 80 | # Manual allocation of port numbers 81 | 82 | If you want to set port numbers yourself, no problem: 83 | 84 | @@@ Sh 85 | $ docker run -d -p 80:80 nginx 86 | $ docker run -d -p 8000:80 nginx 87 | $ docker run -d -p 8080:80 -p 8888:80 nginx 88 | 89 | * We are running two NGINX web servers. 90 | * The first one is exposed on port 80. 91 | * The second one is exposed on port 8000. 92 | * The third one is exposed on ports 8080 and 8888. 93 | 94 | Note: the convention is `port-on-host:port-on-container`. 95 | 96 | 97 | # Plumbing containers into your infrastructure 98 | 99 | There are many ways to integrate containers in your network. 100 | 101 | * Start the container, letting Docker allocate a public port for it. 102 |
Then retrieve that port number and feed it to your configuration. 103 | * Pick a fixed port number in advance, when you generate your configuration. 104 |
Then start your container by setting the port numbers manually. 105 | * Use a network plugin, connecting your containers with e.g. VLANs, tunnels... 106 | * Enable *Swarm Mode* to deploy across a cluster. 107 |
The container will then be reachable through any node of the cluster. 108 | 109 | 110 | # Finding the container's IP address 111 | 112 | We can use the `docker inspect` command to find the IP address of the 113 | container. 114 | 115 | @@@ Sh 116 | $ docker inspect --format '{{ .NetworkSettings.IPAddress }}' 117 | 172.17.0.3 118 | 119 | * `docker inspect` is an advanced command, that can retrieve a ton 120 | of information about our containers. 121 | * Here, we provide it with a format string to extract exactly the 122 | private IP address of the container. 123 | 124 | 125 | # Pinging our container 126 | 127 | We can test connectivity to the container using the IP address we've 128 | just discovered. Let's see this now by using the ``ping`` tool. 129 | 130 | @@@ Sh 131 | $ ping 132 | 64 bytes from : icmp_req=1 ttl=64 time=0.085 ms 133 | 64 bytes from : icmp_req=2 ttl=64 time=0.085 ms 134 | 64 bytes from : icmp_req=3 ttl=64 time=0.085 ms 135 | 136 | 137 | # The different network drivers 138 | 139 | A container can use one of the following drivers: 140 | 141 | * `bridge` (default) 142 | * `none` 143 | * `host` 144 | * `container` 145 | 146 | The driver is selected with `docker run --net ...`. 147 | 148 | 149 | # The default bridge 150 | 151 | * By default, the container gets a virtual `eth0` interface. 152 |
(In addition to its own private `lo` loopback interface.) 153 | * That interface is provided by a `veth` pair. 154 | * It is connected to the Docker bridge. 155 |
(Named `docker0` by default; configurable with `--bridge`.) 156 | * Addresses are allocated on a private, internal subnet. 157 |
(Docker uses 172.17.0.0/16 by default; configurable with `--bip`.) 158 | * Outbound traffic goes through an iptables MASQUERADE rule. 159 | * Inbound traffic goes through an iptables DNAT rule. 160 | * The container can have its own routes, iptables rules, etc. 161 | 162 | 163 | # The null driver 164 | 165 | * Container is started with `docker run --net none ...` 166 | * It only gets the `lo` loopback interface. No `eth0`. 167 | * It can't send or receive network traffic. 168 | * Useful for isolated/untrusted workloads. 169 | 170 | 171 | # The host driver 172 | 173 | * Container is started with `docker run --net host ...` 174 | * It sees (and can access) the network interfaces of the host. 175 | * It can bind any address, any port (for ill and for good). 176 | * Network traffic doesn't have to go through NAT, bridge, or veth. 177 | * Performance = native! 178 | 179 | Use cases: 180 | 181 | * Performance sensitive applications (VOIP, gaming, streaming...) 182 | * Peer discovery (e.g. Erlang port mapper, Raft, Serf...) 183 | 184 | 185 | # The container driver 186 | 187 | * Container is started with `docker run --net container:id ...` 188 | * It re-uses the network stack of another container. 189 | * It shares with this other container the same interfaces, IP address(es), routes, iptables rules, etc. 190 | * Those containers can communicate over their `lo` interface. 191 |
(i.e. one can bind to 127.0.0.1 and the others can connect to it.) 192 | 193 | 194 | # Section summary 195 | 196 | We've learned how to: 197 | 198 | * Expose a network port. 199 | * Manipulate container networking basics. 200 | * Find a container's IP address. 201 | 202 | In the next chapter, we will see how to connect 203 | containers together without exposing their ports. 204 | -------------------------------------------------------------------------------- /slides/Container_Networking_Basics/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Container Networking Basics 3 | 4 | ![A dense graph network](network.jpg) 5 | -------------------------------------------------------------------------------- /slides/Container_Networking_Basics/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Container Networking Basics 3 | 4 | ## Objectives 5 | 6 | We will now run network services (accepting requests) in containers. 7 | 8 | At the end of this lesson, you will be able to: 9 | 10 | * Run a network service in a container. 11 | * Manipulate container networking basics. 12 | * Find a container's IP address. 13 | 14 | We will also explain the different network models used by Docker. 15 | -------------------------------------------------------------------------------- /slides/Container_Networking_Basics/browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Container_Networking_Basics/browser.png -------------------------------------------------------------------------------- /slides/Container_Networking_Basics/network.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Container_Networking_Basics/network.jpg -------------------------------------------------------------------------------- /slides/Container_Networking_Basics/web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Container_Networking_Basics/web.png -------------------------------------------------------------------------------- /slides/Copying_Files_During_Build/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # Build some C code 3 | 4 | We want to build a container that compiles a basic "Hello world" program in C. 5 | 6 | Here is the program, `hello.c`: 7 | 8 | @@@ Sh 9 | int main () { 10 | puts("Hello, world!"); 11 | return 0; 12 | } 13 | 14 | Let's create a new directory, and put this file in there. 15 | 16 | Then we will write the Dockerfile. 17 | 18 | 19 | # The Dockerfile 20 | 21 | On Debian and Ubuntu, the package `build-essential` will get us a compiler. 22 | 23 | When installing it, don't forget to specify the `-y` flag, otherwise the build will fail (since the build cannot be interactive). 24 | 25 | Then we will use `COPY` to place the source file into the container. 26 | 27 | @@@ Sh 28 | FROM ubuntu 29 | RUN apt-get update 30 | RUN apt-get install -y build-essential 31 | COPY hello.c / 32 | RUN make hello 33 | CMD /hello 34 | 35 | Create this Dockerfile. 36 | 37 | 38 | # Testing our C program 39 | 40 | * Create `hello.c` and `Dockerfile` in the same direcotry. 41 | * Run `docker build -t hello .` in this directory. 42 | * Run `docker run hello`, you should see `Hello, world!`. 43 | 44 | Success! 45 | 46 | 47 | # `COPY` and the build cache 48 | 49 | * Run the build again. 50 | * Now, modify `hello.c` and run the build again. 51 | * Docker can cache steps involving `COPY`. 52 | * Those steps will not be executed again if the files haven't been changed. 53 | 54 | 55 | # Details 56 | 57 | * You can `COPY` whole directories recursively. 58 | * Older Dockerfiles also have the `ADD` instruction. 59 |
It is similar but can automatically extract archives. 60 | * If we really wanted to compile C code in a compiler, we would: 61 | 62 | * Place it in a different directory, with the `WORKDIR` instruction. 63 | * Even better, use the `gcc` official image. 64 | -------------------------------------------------------------------------------- /slides/Copying_Files_During_Build/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Copying files during the build 3 | 4 | ![Monks copying books](copy.jpg) 5 | -------------------------------------------------------------------------------- /slides/Copying_Files_During_Build/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Copying files during the build 3 | 4 | ## Objectives 5 | 6 | So far, we have installed things in our container images 7 | by downloading packages. 8 | 9 | We can also copy files from the *build context* to the 10 | container that we are building. 11 | 12 | Remember: the *build context* is the directory containing 13 | the Dockerfile. 14 | 15 | In this chapter, we will learn a new Dockerfile keyword: `COPY`. -------------------------------------------------------------------------------- /slides/Copying_Files_During_Build/copy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Copying_Files_During_Build/copy.jpg -------------------------------------------------------------------------------- /slides/Copying_Files_During_Build/entrypoint.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Copying_Files_During_Build/entrypoint.jpg -------------------------------------------------------------------------------- /slides/Course_Conclusion/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # Course Summary # 3 | 4 | During this class, we: 5 | 6 | * Installed Docker. 7 | * Launched our first container. 8 | * Learned about images. 9 | * Got an understanding about how to manage connectivity and data in 10 | Docker containers. 11 | * Learned how to integrate Docker into your daily workflow. 12 | 13 | 14 | # Questions & Next Steps # 15 | 16 | **Still Learning:** 17 | 18 | * Docker homepage - [http://www.docker.com/](http://www.docker.com/) 19 | * Docker Hub - [https://hub.docker.com](https://hub.docker.com) 20 | * Docker blog - [http://blog.docker.com/](http://blog.docker.com/) 21 | * Docker documentation - [http://docs.docker.com/](http://docs.docker.com/) 22 | * Docker Getting Started Guide - [http://www.docker.com/gettingstarted/](http://www.docker.com/gettingstarted/) 23 | * Docker code on GitHub - [https://github.com/docker/docker](https://github.com/docker/docker) 24 | * Docker mailing list - [https://groups.google.com/forum/#!forum/docker-user](https://groups.google.com/forum/#!forum/docker-user) 25 | * Docker on IRC: irc.freenode.net and channels ``#docker`` and ``#docker-dev`` 26 | * Docker on Twitter - [http://twitter.com/docker](http://twitter.com/docker) 27 | * Get Docker help on Stack Overflow - [http://stackoverflow.com/search?q=docker](http://stackoverflow.com/search?q=docker) 28 | 29 | 30 | 31 |
32 |
33 | # Thank You # 34 |
35 | ![Docker Inc](../_images/DockerLogo.png) 36 | -------------------------------------------------------------------------------- /slides/Course_Conclusion/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Course Conclusion 3 | 4 | ![end](end.jpg) 5 | -------------------------------------------------------------------------------- /slides/Course_Conclusion/end.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Course_Conclusion/end.jpg -------------------------------------------------------------------------------- /slides/Course_Overview/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Course_Overview/.DS_Store -------------------------------------------------------------------------------- /slides/Course_Overview/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # Course Agenda 3 | ## Part 1 4 | 5 | * About Docker 6 | * Using the training virtual machines 7 | * Installing Docker 8 | * Our first containers 9 | * Running containers in the background 10 | * Images and containers 11 | * Building images manually 12 | * Building images automatically 13 | * Basic networking 14 | * Local development workflow 15 | 16 | 17 | # Course Agenda 18 | ## Part 2 19 | 20 | * Working with volumes 21 | * Connecting containers 22 | * Advanced Dockerfiles 23 | * Orchestration 24 | * Ambassadors 25 | * The Docker Hub 26 | * Automated builds 27 | * Security 28 | * The Docker API 29 | 30 | 31 | # Table of Contents 32 | 33 | ~~~TOC~~~ 34 | -------------------------------------------------------------------------------- /slides/Course_Overview/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Introduction to Docker # 3 | 4 | ## Version: ~~~CONFIG:training_version~~~ ## 5 | 6 | ![Docker Inc](logo.png) 7 | 8 | ## An Open Platform to Build, Ship, and Run Distributed Applications ## 9 | 10 | 11 | # Docker Fundamentals Exercises # 12 | 13 | ## Version: ~~~CONFIG:training_version~~~ ## 14 | 15 | ![Docker Inc](logo.png) 16 | -------------------------------------------------------------------------------- /slides/Course_Overview/Intro.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Logistics 4 | 5 | - Updated copy of the slides: http://container.training/ 6 | 7 | - Note: the PDF version has extra slides 8 | 9 | - You should have a little piece of paper, 10 |
with your training VM IP address + credentials 11 | 12 | - Can't find the paper? Raise your hand and ask for one! 13 | 14 | - Backchannel: 15 |
[container.training/chat](http://container.training/chat/) 16 | 17 | - students: feel free to ask questions there 18 | 19 | - TAs: join the channel to answer questions 20 | 21 | -------------------------------------------------------------------------------- /slides/Course_Overview/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Course Overview 3 | 4 | ## You will: 5 | 6 | * Learn what Docker is and what it is for. 7 | * Learn the terminology, and define images, containers, etc. 8 | * Learn how to install Docker. 9 | * Use Docker to run containers. 10 | * Use Docker to build containers. 11 | * Learn how to orchestrate Docker containers. 12 | * Interact with the Docker Hub website. 13 | * Acquire tips and good practice. 14 | * Know what's next: the future of Docker, and how to get help. 15 | -------------------------------------------------------------------------------- /slides/Course_Overview/Toc.md: -------------------------------------------------------------------------------- 1 | 2 | # Part 1 3 | 4 | - About Docker 5 | - Your training Virtual Machine 6 | - Install Docker 7 | - Our First Containers 8 | - Background Containers 9 | - Restarting and Attaching to Containers 10 | - Understanding Docker Images 11 | - Building Docker images 12 | - Advanced Dockerfiles 13 | - A quick word about the Docker Hub 14 | 15 | 16 | # Part 2 17 | 18 | - Naming and inspecting containers 19 | - Introduction to Container Networking 20 | - Container Network Model 21 | - (Connecting Containers with Links) 22 | - (Ambassadors) 23 | - Local Development Workflow with Docker 24 | - Working with Volumes 25 | - Compose For Development Stacks 26 | 27 | 28 | # Table of Contents 29 | 30 | ~~~TOC~~~ 31 | -------------------------------------------------------------------------------- /slides/Course_Overview/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Course_Overview/logo.png -------------------------------------------------------------------------------- /slides/Docker_API/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # The Docker API 3 | 4 | -------------------------------------------------------------------------------- /slides/Docker_API/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: The Docker API 3 | 4 | ## Objectives 5 | 6 | At the end of this lesson, you will be able to: 7 | 8 | * Work with the Docker API. 9 | * Create and manage containers with the Docker API. 10 | * Manage images with the Docker API. 11 | -------------------------------------------------------------------------------- /slides/Docker_Hub_Advanced/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # Using the Docker Hub 3 | 4 | We have built our own container image. 5 | 6 | This image would be useful to the whole team but how do we share it? 7 | 8 | Using the [Docker Hub](http://hub.docker.com/)! 9 | 10 | 11 | # Pulling images 12 | 13 | Earlier in this training we saw how to pull images down from the Docker Hub. 14 | 15 | @@@ Sh 16 | $ docker pull ubuntu:14.04 17 | 18 | This will connect to the Docker Hub and download the ``ubuntu:14.04`` 19 | image to allow us to build containers from it. 20 | 21 | We can also do the reverse and push an image to the Docker Hub so that others 22 | can use it. 23 | 24 | 25 | # Before pushing a Docker image ... 26 | 27 | We push images using the ``docker push`` command. 28 | 29 | Images are uploaded via HTTP and authenticated. 30 | 31 | You can only push images to the *user namespace*, and with your 32 | own username. 33 | 34 | This means that you cannot push an image called ``web``. 35 | 36 | It has to be called ``/web``. 37 | 38 | 39 | # Name your image properly 40 | 41 | Here are different ways to ensure that your image has the right name. 42 | 43 | Of course, in the examples below, replace ```` 44 | with your actual login on the Docker Hub. 45 | 46 | * If you have previously built the ``ifconfigme`` image, you can re-tag it: 47 | 48 | @@@ Sh 49 | $ docker tag ifconfigme /ifconfigme 50 | 51 | * Or, you can also rebuild it from scratch: 52 | 53 | @@@ Sh 54 | $ docker build -t /ifconfigme \ 55 | git://github.com/jpetazzo/ifconfigme.git 56 | 57 | 58 | # Pushing a Docker image to the Docker Hub 59 | 60 | Now that the image is named properly, we can push it: 61 | 62 | @@@ Sh 63 | $ docker push /ifconfigme 64 | 65 | You will be prompted for a user name and password. 66 | 67 | (Unless you already did ``docker login`` earlier.) 68 | 69 | @@@ Sh 70 | Please login prior to push: 71 | Username: 72 | Password: ********* 73 | Email: ... 74 | Login Succeeded 75 | 76 | You will login using your Docker Hub name, account and email address you 77 | created earlier in the training. 78 | 79 | 80 | # More about pushing an image 81 | 82 | * If the image doesn't exist on the Docker Hub, a new repository will be 83 | created. 84 | * You can push an updated image on top of an existing image. Only the 85 | layers which have changed will be updated. 86 | * When you pull down the resulting image, only the updates will need to 87 | be downloaded. 88 | 89 | 90 | # Viewing our uploaded image 91 | 92 | Let's sign onto the [Docker Hub](https://hub.docker.com/) and review 93 | our uploaded image. 94 | 95 | Browse to: 96 | 97 | @@@ Sh 98 | https://hub.docker.com/ 99 | 100 | ![frontpage](frontpage.png) 101 | 102 | 103 | # Logging in to the Docker Hub 104 | 105 | Now click the ``Login`` link and fill in the ``Username`` and 106 | ``Password`` fields. 107 | 108 | And clicking the ``Log In`` button. 109 | 110 | ![login](login.png) 111 | 112 | 113 | # Your account screen 114 | 115 | This is the master account screen. Here you can see your repositories and recent activity. 116 | 117 | ![account](account.png) 118 | 119 | 120 | # Review your webapp repository 121 | 122 | Click on the link to your ``/web`` repository. 123 | 124 | ![repopage](trainrepo.png) 125 | 126 | * You can see the basic information about your image. 127 | * You can also browse to the ``Tags`` tab to see image tags, or navigate to a link in the "Settings" sidebar to configure the repo. 128 | 129 | 130 | # Automated Builds 131 | 132 | In addition to pushing images to Docker Hub you can also create special 133 | images called *Automated Builds*. An *Automated Build* is created from a 134 | ``Dockerfile`` in a GitHub repository. 135 | 136 | This provides a guarantee that the image came from a specific source and 137 | allows you to ensure that any downloaded image is built from a 138 | ``Dockerfile`` you can review. 139 | 140 | 141 | # Creating an Automated build 142 | 143 | To create an *Automated Build* click on the ``Add Repository`` button on your main 144 | account screen and select ``Automated Build``. 145 | 146 | ![addautomated](addautomated.png) 147 | 148 | 149 | # Connecting your GitHub account 150 | 151 | If this is your first *Automated Build* you will be prompted to connect 152 | your GitHub account to the Docker Hub. 153 | 154 | ![github](github.png) 155 | 156 | 157 | # Select specific GitHub repository 158 | 159 | You can then select a specific GitHub repository. 160 | 161 | It must contain a ``Dockerfile``. 162 | 163 | ![githubrepo](githubrepo.png) 164 | 165 | If you don't have a repository with a Dockerfile, you can 166 | fork https://github.com/docker-training/staticweb, for instance. 167 | 168 | 169 | # Configuring Automated Build 170 | 171 | You can then configure the specifics of your *Automated Build* and click 172 | the ``Create Repository`` button. 173 | 174 | ![configtrusted](configtrusted.png) 175 | 176 | 177 | # Automated Building 178 | 179 | Once configured your *Automated Build* will automatically start building 180 | an image from the ``Dockerfile`` contained in your Git repository. 181 | 182 | Every time you make a commit to that repository a new version of the 183 | image will be built. 184 | 185 | 186 | # Section summary 187 | 188 | We've learned how to: 189 | 190 | * Pull and push images to the Docker Hub. 191 | * Explore the Docker Hub. 192 | * Understand and create *Automated Builds*. 193 | 194 | 195 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Push your web image 196 | 197 | 1. Run the ``docker push`` command. 198 | 199 | @@@ Sh 200 | $ docker push /web 201 | 202 | 2. Login into your Docker Hub account using your user name, password 203 | and email. 204 | 205 | 3. Confirm your image was successfully pushed. 206 | 207 | 208 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Review your pushed image 209 | 210 | 1. Browse to the Docker Hub. 211 | 212 | @@@ Sh 213 | https://hub.docker.com/ 214 | 215 | 2. Click on the Login link. 216 | 217 | @@@ Sh 218 | https://hub.docker.com/account/login/ 219 | 220 | 3. Login using your user name and password. 221 | 222 | 223 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: View your image repository 224 | 225 | 1. Browse to your new image repository, either by clicking on the link or by 226 | visiting the following URL: 227 | 228 | @@@ Sh 229 | https://registry.hub.docker.com/u//staticweb/ 230 | 231 | 2. Explore the tabs and settings available to you. 232 | 233 | 234 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Create an automated build 235 | 236 | To create an *Automated Build* click on the ``Add Repository`` button on your main 237 | account screen and select ``Automated Build``. 238 | 239 | ![addautomated](addautomated.png) 240 | 241 | 242 | # Connecting to your Github account 243 | 244 | If this is your first *Automated Build* you will be prompted to connect 245 | your GitHub account to the Docker Hub. 246 | 247 | ![github](github.png) 248 | 249 | 250 | 251 | 252 | # Connecting to your Github account 253 | 254 | You can then select a specific GitHub repository. 255 | 256 | It must contain a ``Dockerfile``. 257 | 258 | ![githubrepo](githubrepo.png) 259 | 260 | If you don't have a repository with a Dockerfile, you can 261 | fork `https://github.com/docker-training/staticweb`, for instance. 262 | 263 | 264 | 265 | # Configuring an automated build 266 | 267 | You can then configure the specifics of your *Automated Build* and click 268 | the ``Create Repository`` button. 269 | 270 | ![configtrusted](configtrusted.png) 271 | -------------------------------------------------------------------------------- /slides/Docker_Hub_Advanced/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Using the Docker Hub 3 | 4 | -------------------------------------------------------------------------------- /slides/Docker_Hub_Advanced/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Using the Docker Hub 3 | 4 | ## Objectives 5 | 6 | At the end of this lesson, you will be able to: 7 | 8 | * Pull and push images to the Docker Hub. 9 | * Explore the Docker Hub. 10 | * Understand and create *Automated Builds*. 11 | -------------------------------------------------------------------------------- /slides/Docker_Hub_Advanced/account.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Advanced/account.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Advanced/addautomated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Advanced/addautomated.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Advanced/addtrusted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Advanced/addtrusted.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Advanced/configtrusted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Advanced/configtrusted.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Advanced/frontpage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Advanced/frontpage.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Advanced/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Advanced/github.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Advanced/githublinked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Advanced/githublinked.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Advanced/githubrepo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Advanced/githubrepo.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Advanced/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Advanced/login.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Advanced/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Advanced/settings.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Advanced/tags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Advanced/tags.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Advanced/trainrepo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Advanced/trainrepo.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # Sign up for a Docker Hub account 3 | 4 | Note: if you already have an account on the Index/Hub, don't create another one. 5 | 6 | - Having a Docker Hub account will allow us to store our images in the registry. 7 | - To sign up, you'll go to [hub.docker.com](http://hub.docker.com) and fill out the form. 8 | - Note: your Docker Hub username has to be all lowercase. 9 | 10 | ![Register](registerhub.png) 11 | 12 | 13 | # Activate your account through e-mail. 14 | 15 | - Check your e-mail and click the confirmation link. 16 | 17 | 18 | # Login 19 | Let's use our new account to login to the Docker Hub! 20 | 21 | @@@ Sh 22 | $ docker login 23 | Username: my_docker_hub_login 24 | Password: 25 | Email: my@email.com 26 | Login Succeeded 27 | 28 | Our credentials will be stored in ``~/.dockercfg``. 29 | 30 | 31 | # The ``.dockercfg`` configuration file 32 | 33 | The ``~/.dockercfg`` configuration file holds our Docker registry 34 | authentication credentials. 35 | 36 | @@@ Sh 37 | { 38 | "https://index.docker.io/v1/": { 39 | "auth":"amFtdHVyMDE6aTliMUw5ckE=", 40 | "email":"education@docker.com" 41 | } 42 | } 43 | 44 | The ``auth`` section is Base64 encoding of your user name and password. 45 | 46 | It should be owned by your user with permissions of ``0600``. 47 | 48 | **You should protect this file!** 49 | 50 | 51 | # Navigating Docker Hub 52 | 53 | ![Navigating](dockerhub.png) 54 | 55 | 56 | # Repositories 57 | 58 | - Store all public and private images in the registry 59 | - Apply to your namespace 60 | - Empty! 61 | 62 | ![Repositories](blankrepositories.png) 63 | 64 | 65 | # Public Repositories 66 | 67 | - Docker Hub provides access to tens of thousands of pre-made images that you can build from. 68 | - Some of these are `official builds` and live in the root namespace. 69 | - Most are community contributed and maintained. 70 | 71 | ![Public Repositories](publicrepos.png) 72 | 73 | 74 | # Official Repositories 75 | 76 | - Are maintained by the product owners 77 | - Blessed by Docker 78 | 79 | ![Official Repositories](officialrepos.png) 80 | 81 | 82 | # New Repository (1/3) 83 | 84 | - Pull down `Add Repository` menu and select `Repository` 85 | 86 | ![New Repository](addrepo.png) 87 | 88 | 89 | # New Repository (2/3) 90 | 91 | - Leave `namespace` at the default (your username) 92 | - Give your repository a name 93 | - Type a brief description so people know what it is 94 | - Leave `Public` selected 95 | - Submit the form with `Add Repository` button (not shown) 96 | 97 | ![Repository Form](addrepo2.png) 98 | 99 | 100 | # New Repository (3/3) 101 | 102 | - Click `Repositories` and you will see your new repository. 103 | - You can push images to this repository from the `docker` commandline. 104 | - More on this later. 105 | 106 | ![Repository List](addrepo3.png) 107 | 108 | 109 | # Repository Settings 110 | 111 | You can change the following: 112 | 113 | - Repository Description 114 | - Webhooks 115 | - Collaborators 116 | - Mark as unlisted in the global search (NOT a private repository) 117 | 118 | ![Repository Settings](settings.png) 119 | 120 | 121 | # Collaborators 122 | 123 | You can invite other Docker Hub to collaborate on your projects. 124 | 125 | - Collaborators cannot change settings in the repository. 126 | - Collaborators can push images to the repository. 127 | 128 | ![Collaborators](collab.png) 129 | 130 | 131 | # Webhooks 132 | 133 | - Notify external applications that an image has been uploaded to the repository. 134 | - Powerful tool for integrating with your development workflow. 135 | - Even more powerful when used with Automated Builds. 136 | 137 | ![Webhooks](webhooks.png) 138 | 139 | 140 | # Automated Builds 141 | 142 | - Automatically build an image when source code is changed. 143 | - Integrated with Github and Bitbucket 144 | - Work with public and private repositories 145 | - Add the same as a regular repository, select `Automated Build` from the `Add Repository` menu 146 | - We'll set one of these up later! 147 | - You will need a Github account to follow along later, so go ahead and create one now if you don't 148 | have one yet. 149 | 150 | 151 | # Section summary 152 | 153 | We've learned how to: 154 | 155 | * Register for an account on Docker Hub. 156 | * Login to your account from the command line. 157 | * Access some special Docker Hub features for better workflows. 158 | 159 | 160 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Register an account with Docker Hub 161 | 162 | 1. Go to [hub.docker.com](https://hub.docker.com) and fill out the form to register an account. 163 | 2. Click the activation link in the e-mail you have been sent to confirm. 164 | 165 | 166 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Logging in to Docker Hub 167 | 168 | 1. Login to the Docker Hub on the command line now. You'll need the 169 | user name and password you created in Lab 1.1. 170 | 171 | @@@ Sh 172 | $ docker login 173 | 174 | 2. You should see and type: 175 | 176 | @@@ Sh 177 | Username: myDockerHubusername 178 | Password: 179 | Email: my@email.com 180 | Login Succeeded 181 | 182 | 3. Check the contents of the ``~/.dockercfg`` file. 183 | 184 | @@@ Sh 185 | $ cat ~/.dockercfg 186 | { 187 | "https://index.docker.io/v1/": { 188 | "auth":"amFtdHVyMDE6aTliMUw5ckE=", 189 | "email":"education@docker.com" 190 | } 191 | } 192 | 193 | 194 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Set up a Github account 195 | 196 | If you don't have a Github account, go ahead and set one up now. We will need to use this later 197 | for creating Automated Builds, a feature of Docker Hub that allows you to automatically re-build 198 | an image when the source code contained within that image changes. 199 | 200 | ![](octocat.png) 201 | -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Introducing Docker Hub 3 | 4 | ![Docker Hub](dockerhub.png) 5 | -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Introducing Docker Hub 3 | 4 | ## Objectives 5 | 6 | At the end of this lesson, you will be able to: 7 | 8 | * Register for an account on Docker Hub. 9 | * Login to your account from the command line. 10 | * Learn about how Docker Hub works. 11 | * Learn about how to integrate Docker Hub into your development workflow. 12 | -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/addrepo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/addrepo.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/addrepo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/addrepo2.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/addrepo3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/addrepo3.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/autobuild-build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/autobuild-build.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/autobuild-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/autobuild-config.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/autobuild-config2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/autobuild-config2.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/autobuild-select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/autobuild-select.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/autobuild-success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/autobuild-success.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/blankrepositories.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/blankrepositories.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/collab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/collab.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/dockerhub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/dockerhub.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/octocat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/octocat.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/officialrepos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/officialrepos.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/provider-auth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/provider-auth.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/provider-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/provider-login.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/provider-perms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/provider-perms.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/provider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/provider.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/publicrepos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/publicrepos.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/registerhub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/registerhub.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/settings.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Intro/webhooks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Intro/webhooks.png -------------------------------------------------------------------------------- /slides/Docker_Hub_Tease/Body.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Docker_Hub_Tease/Body.md -------------------------------------------------------------------------------- /slides/Docker_Hub_Tease/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # A quick word about the Docker Hub 3 | -------------------------------------------------------------------------------- /slides/Docker_Hub_Tease/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Uploading our images to the Docker Hub 3 | 4 | We have built our first images. 5 | 6 | If we were so inclined, we could share those images through the Docker Hub. 7 | 8 | We won't do it since we don't want to force everyone to create a Docker Hub account (although it's free, yay!) but the steps would be: 9 | 10 | * have an account on the Docker Hub 11 | * tag our image accordingly (i.e. `username/imagename`) 12 | * `docker push username/imagename` 13 | 14 | Anybody can now `docker run username/imagename` from any Docker host. 15 | 16 | Images can be set to be private as well. 17 | -------------------------------------------------------------------------------- /slides/Dockerfile_Reference/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Advanced Dockerfiles 3 | 4 | ![construction](construction.jpg) 5 | -------------------------------------------------------------------------------- /slides/Dockerfile_Reference/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Advanced Dockerfiles 3 | 4 | ## Objectives 5 | 6 | We have seen simple Dockerfiles to illustrate how Docker build 7 | container images. In this chapter, we will see: 8 | 9 | * The syntax and keywords that can be used in Dockerfiles. 10 | * Tips and tricks to write better Dockerfiles. 11 | -------------------------------------------------------------------------------- /slides/Dockerfile_Reference/construction.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Dockerfile_Reference/construction.jpg -------------------------------------------------------------------------------- /slides/Dockerfile_Reference/webapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Dockerfile_Reference/webapp.png -------------------------------------------------------------------------------- /slides/First_Containers/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # Docker architecture 3 | 4 | Docker is a client-server application. 5 | 6 | * **The Docker Engine (or "daemon")** 7 |
Receives and processes incoming Docker API requests. 8 | 9 | * **The Docker client** 10 |
Talks to the Docker daemon via the Docker API. 11 |
We'll use mostly the CLI embedded within the `docker` binary. 12 | 13 | * **Docker Hub Registry** 14 |
Collection of public images. 15 |
The Docker daemon talks to it via the registry API. 16 | 17 | 18 | # Hello World 19 | 20 | In your Docker environment, just run the following command: 21 | 22 | @@@ Sh 23 | $ docker run busybox echo hello world 24 | hello world 25 | 26 | 27 | 28 | # That was our first container! 29 | 30 | * We used one of the smallest, simplest images available: `busybox`. 31 | * `busybox` is typically used in embedded systems (phones, routers...) 32 | * We ran a single process and echo'ed `hello world`. 33 | 34 | 35 | 36 | # A more useful container 37 | 38 | Let's run a more exciting container: 39 | 40 | @@@ Sh 41 | $ docker run -it ubuntu 42 | root@04c0bb0a6c07:/# 43 | 44 | * This is a brand new container. 45 | * It runs a bare-bones, no-frills `ubuntu` system. 46 | * `-it` is shorthand for `-i -t`. 47 | 48 | * `-i` tells Docker to connect us to the container's stdin. 49 | * `-t` tells Docker that we want a pseudo-terminal. 50 | 51 | 52 | 53 | 54 | # Do something in our container 55 | 56 | Try to run `figlet` in our container. 57 | 58 | @@@ Sh 59 | root@04c0bb0a6c07:/# figlet hello 60 | bash: figlet: command not found 61 | 62 | Alright, we need to install it. 63 | 64 | 65 | # An observation 66 | 67 | Let's check how many packages are installed here. 68 | 69 | @@@ Sh 70 | root@04c0bb0a6c07:/# dpkg -l | wc -l 71 | 189 72 | 73 | * `dpkg -l` lists the packages installed in our container 74 | * `wc -l` counts them 75 | * If you have a Debian or Ubuntu machine, you can run the same command 76 | and compare the results. 77 | 78 | 79 | # Install a package in our container 80 | 81 | We want `figlet`, so let's install it: 82 | 83 | @@@ Sh 84 | root@04c0bb0a6c07:/# apt-get update 85 | ... 86 | Fetched 1514 kB in 14s (103 kB/s) 87 | Reading package lists... Done 88 | root@04c0bb0a6c07:/# apt-get install figlet 89 | Reading package lists... Done 90 | ... 91 | 92 | One minute later, `figlet` is installed! 93 | 94 | @@@ Sh 95 | # figlet hello 96 | _ _ _ 97 | | |__ ___| | | ___ 98 | | '_ \ / _ \ | |/ _ \ 99 | | | | | __/ | | (_) | 100 | |_| |_|\___|_|_|\___/ 101 | 102 | 103 | 104 | # Exiting our container 105 | 106 | Just exit the shell, like you would usually do. 107 | 108 | (E.g. with `^D` or `exit`) 109 | 110 | @@@ Sh 111 | root@04c0bb0a6c07:/# exit 112 | 113 | * Our container is now in a *stopped* state. 114 | 115 | * It still exists on disk, but all compute resources have been freed up. 116 | 117 | 118 | 119 | # Starting another container 120 | 121 | What if we start a new container, and try to run `figlet` again? 122 | 123 | @@@ Sh 124 | $ docker run -it ubuntu 125 | root@b13c164401fb:/# figlet 126 | bash: figlet: command not found 127 | 128 | * We started a *brand new container*. 129 | * The basic Ubuntu image was used, and `figlet` is not here. 130 | * We will see in the next chapters how to bake a custom image with `figlet`. 131 | 132 | -------------------------------------------------------------------------------- /slides/First_Containers/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Our First Containers 3 | 4 | ![Plastic Containers](firstcontainers.jpg) 5 | -------------------------------------------------------------------------------- /slides/First_Containers/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Our First Containers 3 | 4 | ## Objectives 5 | 6 | At the end of this lesson, you will have: 7 | 8 | * Seen Docker in action. 9 | * Started your first containers. -------------------------------------------------------------------------------- /slides/First_Containers/firstcontainers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/First_Containers/firstcontainers.jpg -------------------------------------------------------------------------------- /slides/First_Containers/superman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/First_Containers/superman.png -------------------------------------------------------------------------------- /slides/Initial_Images/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # What is an image? 3 | 4 | * An image is a collection of files + some meta data. 5 |
(Technically: those files form the root filesystem of a container.) 6 | * Images are made of *layers*, conceptually stacked on top of each other. 7 | * Each layer can add, change, and remove files. 8 | * Images can share layers to optimize disk usage, transfer times, and memory use. 9 | 10 | * Example: 11 | * CentOS 12 | * JRE 13 | * Tomcat 14 | * Dependencies 15 | * Application JAR 16 | * Configuration 17 | 18 | 19 | # Differences between containers and images 20 | 21 | * An image is a read-only filesystem. 22 | * A container is an encapsulated set of processes running in a 23 | read-write copy of that filesystem. 24 | * To optimize container boot time, *copy-on-write* is used 25 | instead of regular copy. 26 | * `docker run` starts a container from a given image. 27 | 28 | Let's give a couple of metaphors to illustrate those concepts. 29 | 30 | 31 | # Image as stencils 32 | 33 | Images are like templates or stencils that you can create containers from. 34 | 35 | ![stencil](stenciling-wall.jpg) 36 | 37 | 38 | # Object-oriented programming 39 | 40 | * Images are conceptually similar to *classes*. 41 | * Layers are conceptually similar to *inheritance*. 42 | * Containers are conceptually similar to *instances*. 43 | 44 | 45 | # Wait a minute... 46 | 47 | If an image is read-only, how do we change it? 48 | 49 | * We don't. 50 | * We create a new container from that image. 51 | * Then we make changes to that container. 52 | * When we are satisfied with those changes, we transform them into a new layer. 53 | * A new image is created by stacking the new layer on top of the old image. 54 | 55 | 56 | # A chicken-and-egg problem 57 | 58 | * The only way to create an image is by "freezing" a container. 59 | * The only way to create a container is by instanciating an image. 60 | * Help! 61 | 62 | 63 | # Creating the first images 64 | 65 | There is a special empty image called `scratch`. 66 | 67 | * It allows to *build from scratch*. 68 | 69 | The `docker import` command loads a tarball into Docker. 70 | 71 | * The imported tarball becomes a standalone image. 72 | * That new image has a single layer. 73 | 74 | Note: you will probably never have to do this yourself. 75 | 76 | 77 | # Creating other images 78 | 79 | `docker commit` 80 | 81 | * Saves all the changes made to a container into a new layer. 82 | * Creates a new image (effectively a copy of the container). 83 | 84 | `docker build` 85 | 86 | * Performs a repeatable build sequence. 87 | * This is the preferred method! 88 | 89 | We will explain both methods in a moment. 90 | 91 | 92 | # Images namespaces 93 | 94 | There are three namespaces: 95 | 96 | * Official images 97 | 98 | e.g. `ubuntu`, `busybox` ... 99 | 100 | * User (and organizations) images 101 | 102 | e.g. `jpetazzo/clock` 103 | 104 | * Self-hosted images 105 | 106 | e.g. `registry.example.com:5000/my-private/image` 107 | 108 | Let's explain each of them. 109 | 110 | 111 | # Root namespace 112 | 113 | The root namespace is for official images. They are put there by Docker Inc., 114 | but they are generally authored and maintained by third parties. 115 | 116 | Those images include: 117 | 118 | * Small, "swiss-army-knife" images like busybox. 119 | * Distro images to be used as bases for your builds, like ubuntu, fedora... 120 | * Ready-to-use components and services, like redis, postgresql... 121 | 122 | 123 | 124 | # User namespace 125 | 126 | The user namespace holds images for Docker Hub users and organizations. 127 | 128 | For example: 129 | 130 | @@@ Sh 131 | jpetazzo/clock 132 | 133 | The Docker Hub user is: 134 | 135 | @@@ Sh 136 | jpetazzo 137 | 138 | The image name is: 139 | 140 | @@@ Sh 141 | clock 142 | 143 | 144 | # Self-Hosted namespace 145 | 146 | This namespace holds images which are not hosted on Docker Hub, but on third 147 | party registries. 148 | 149 | They contain the hostname (or IP address), and optionally the port, of the 150 | registry server. 151 | 152 | For example: 153 | 154 | @@@ Sh 155 | localhost:5000/wordpress 156 | 157 | * `localhost:5000` is the host and port of the registry 158 | * `wordpress` is the name of the image 159 | 160 | 161 | # How do you store and manage images? 162 | 163 | Images can be stored: 164 | 165 | * On your Docker host. 166 | * In a Docker registry. 167 | 168 | You can use the Docker client to download (pull) or upload (push) images. 169 | 170 | To be more accurate: you can use the Docker client to tell a Docker server 171 | to push and pull images to and from a registry. 172 | 173 | 174 | # Showing current images 175 | 176 | Let's look at what images are on our host now. 177 | 178 | @@@ Sh 179 | $ docker images 180 | REPOSITORY TAG IMAGE ID CREATED SIZE 181 | fedora latest ddd5c9c1d0f2 3 days ago 204.7 MB 182 | centos latest d0e7f81ca65c 3 days ago 196.6 MB 183 | ubuntu latest 07c86167cdc4 4 days ago 188 MB 184 | redis latest 4f5f397d4b7c 5 days ago 177.6 MB 185 | postgres latest afe2b5e1859b 5 days ago 264.5 MB 186 | alpine latest 70c557e50ed6 5 days ago 4.798 MB 187 | debian latest f50f9524513f 6 days ago 125.1 MB 188 | busybox latest 3240943c9ea3 2 weeks ago 1.114 MB 189 | training/namer latest 902673acc741 9 months ago 289.3 MB 190 | jpetazzo/clock latest 12068b93616f 12 months ago 2.433 MB 191 | 192 | 193 | 194 | # Searching for images 195 | 196 | We cannot list *all* images on a remote registry, but 197 | we can search for a specific keyword: 198 | 199 | @@@ Sh 200 | $ docker search zookeeper 201 | NAME DESCRIPTION STARS OFFICIAL AUTOMATED 202 | jplock/zookeeper Builds a docker image ... 103 [OK] 203 | mesoscloud/zookeeper ZooKeeper 42 [OK] 204 | springxd/zookeeper A Docker image that ca... 5 [OK] 205 | elevy/zookeeper ZooKeeper configured t... 3 [OK] 206 | 207 | 208 | * "Stars" indicate the popularity of the image. 209 | * "Official" images are those in the root namespace. 210 | * "Automated" images are built automatically by the Docker Hub. 211 |
(This means that their build recipe is always available.) 212 | 213 | 214 | # Downloading images 215 | 216 | There are two ways to download images. 217 | 218 | * Explicitly, with `docker pull`. 219 | * Implicitly, when executing `docker run` and the image is not found locally. 220 | 221 | 222 | # Pulling an image 223 | 224 | @@@ Sh 225 | $ docker pull debian:jessie 226 | Pulling repository debian 227 | b164861940b8: Download complete 228 | b164861940b8: Pulling image (jessie) from debian 229 | d1881793a057: Download complete 230 | 231 | * As seen previously, images are made up of layers. 232 | * Docker has downloaded all the necessary layers. 233 | * In this example, `:jessie` indicates which exact version of Debian 234 | we would like. It is a *version tag*. 235 | 236 | 237 | # Image and tags 238 | 239 | * Images can have tags. 240 | * Tags define image versions or variants. 241 | * `docker pull ubuntu` will refer to `ubuntu:latest`. 242 | * The `:latest` tag is generally updated often. 243 | 244 | 245 | # When to (not) use tags 246 | 247 | Don't specify tags: 248 | 249 | * When doing rapid testing and prototyping. 250 | * When experimenting. 251 | * When you want the latest version. 252 | 253 | Do specify tags: 254 | 255 | * When recording a procedure into a script. 256 | * When going to production. 257 | * To ensure that the same version will be used everywhere. 258 | * To ensure repeatability later. 259 | 260 | 261 | # Section summary 262 | 263 | We've learned how to: 264 | 265 | * Understand images and layers. 266 | * Understand Docker image namespacing. 267 | * Search and download images. 268 | 269 | 270 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Find an image 271 | 272 | 1. Run the ``docker search`` command. 273 | 274 | @@@ Sh 275 | $ docker search training 276 | 277 | 2. You should see something like: 278 | 279 | @@@ Sh 280 | NAME DESCRIPTION STARS OFFICIAL AUTOMATED 281 | training/jenkins 0 [OK] 282 | training/webapp 0 [OK] 283 | training/ls 0 [OK] 284 | training/namer 0 [OK] 285 | training/postgres 0 [OK] 286 | training/notes 0 [OK] 287 | training/docker-fundamentals-image 0 [OK] 288 | training/showoff 0 289 | . . . 290 | 291 | 292 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Retrieve a user image 293 | 294 | 1. Pull down the ``training/docker-fundamentals-image`` image using the 295 | ``docker pull`` command. 296 | 297 | @@@ Sh 298 | $ docker pull training/docker-fundamentals-image 299 | Pulling repository training/docker-fundamentals-image 300 | 8144a5b2bc0c: Pulling dependent layers 301 | 511136ea3c5a: Download complete 302 | 8abc22fbb042: Download complete 303 | 304 | 305 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Show currently installed images 306 | 307 | 1. View the currently installed images using the ``docker images`` 308 | command. 309 | 310 | @@@ Sh 311 | $ docker images 312 | REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE 313 | training/docker-fundamentals-image latest 8144a5b2bc0c 5 days ago 835 MB 314 | ubuntu 13.10 9f676bd305a4 7 weeks ago 178 MB 315 | ubuntu saucy 9f676bd305a4 7 weeks ago 178 MB 316 | ubuntu raring eb601b8965b8 7 weeks ago 166.5 MB 317 | ubuntu 13.04 eb601b8965b8 7 weeks ago 166.5 MB 318 | ubuntu 12.10 5ac751e8d623 7 weeks ago 161 MB 319 | ubuntu quantal 5ac751e8d623 7 weeks ago 161 MB 320 | ubuntu 10.04 9cc9ea5ea540 7 weeks ago 180.8 MB 321 | ubuntu lucid 9cc9ea5ea540 7 weeks ago 180.8 MB 322 | ubuntu 12.04 9cd978db300e 7 weeks ago 204.4 MB 323 | ubuntu latest 9cd978db300e 7 weeks ago 204.4 MB 324 | ubuntu precise 9cd978db300e 7 weeks ago 204.4 MB 325 | 326 | 327 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Retrieve a tagged image 328 | 329 | 1. Pull down a tagged image using the ``docker pull`` command. 330 | 331 | @@@ Sh 332 | $ docker pull debian:jessie 333 | Pulling repository debian 334 | 58394af37342: Download complete 335 | 511136ea3c5a: Download complete 336 | 8abc22fbb042: Download complete 337 | -------------------------------------------------------------------------------- /slides/Initial_Images/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Understanding Docker Images 3 | 4 | ![image](image.png) 5 | -------------------------------------------------------------------------------- /slides/Initial_Images/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Understanding Docker Images 3 | 4 | ## Objectives 5 | 6 | In this lesson, we will explain: 7 | 8 | * What is an image. 9 | * What is a layer. 10 | * The various image namespaces. 11 | * How to search and download images. 12 | * Image tags and when to use them. 13 | -------------------------------------------------------------------------------- /slides/Initial_Images/docker-filesystems-multilayer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Initial_Images/docker-filesystems-multilayer.png -------------------------------------------------------------------------------- /slides/Initial_Images/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Initial_Images/image.png -------------------------------------------------------------------------------- /slides/Initial_Images/stenciling-wall.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Initial_Images/stenciling-wall.jpg -------------------------------------------------------------------------------- /slides/Install_Docker/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # Installing Docker 3 | 4 | Docker is easy to install. 5 | 6 | It runs on: 7 | 8 | * A variety of Linux distributions. 9 | * OS X via a virtual machine. 10 | * Microsoft Windows via a virtual machine. 11 | 12 | 13 | # Installing Docker on Linux 14 | 15 | It can be installed via: 16 | 17 | * Distribution-supplied packages on virtually all distros. 18 | 19 | (Includes at least: Arch Linux, CentOS, Debian, Fedora, Gentoo, 20 | openSUSE, RHEL, Ubuntu.) 21 | 22 | * Packages supplied by Docker. 23 | * Installation script from Docker. 24 | * Binary download from Docker (it's a single file). 25 | 26 | 27 | # Installing Docker with upstream packages 28 | 29 | * Preferred method to install Docker on Linux. 30 | * Upstream's packages are more up-to-date than distros'. 31 | * Instructions per distro: 32 |
https://docs.docker.com/engine/installation/linux/ 33 | * Package will be named `docker-engine`. 34 | 35 | 36 | # Installing Docker with distros packages 37 | 38 | On Red Hat derivatives (Fedora, CentOS): 39 | 40 | @@@ Sh 41 | $ sudo yum install docker 42 | 43 | On Debian and derivatives: 44 | 45 | @@@ Sh 46 | $ sudo apt-get install docker.io 47 | 48 | 49 | # Installation script from Docker 50 | 51 | You can use the ``curl`` command to install on several platforms: 52 | 53 | @@@ Sh 54 | $ curl -s https://get.docker.com/ | sudo sh 55 | 56 | This currently works on: 57 | 58 | * Ubuntu 59 | * Debian 60 | * Fedora 61 | * Gentoo 62 | 63 | 64 | # Installing on OS X and Microsoft Windows 65 | 66 | Docker doesn't run natively on OS X or Microsoft Windows. 67 | 68 | There are three ways to get Docker on OS X or Windows: 69 | 70 | * Using Docker Mac or Docker Windows (recommended); 71 | * Using the Docker Toolbox (formerly recommended); 72 | * Rolling your own with e.g. Parallels, VirtualBox, VMware... 73 | 74 | 75 | # Running Docker on OS X and Windows 76 | 77 | When you execute `docker version` from the terminal: 78 | 79 | * the CLI connects to the Docker Engine over a standard socket, 80 | * the Docker Engine is, in fact, running in a VM, 81 | * ... but the CLI doesn't know or care about that, 82 | * the CLI sends a request using the REST API, 83 | * the Docker Engine in the VM processes the request, 84 | * the CLI gets the response and displays it to you. 85 | 86 | All communication with the Docker Engine happens over the API. 87 | 88 | This will also allow to use remote Engines exactly as if they were local. 89 | 90 | 91 | # Rolling your own install 92 | 93 | * Good luck, you're on your own! 94 | * There is (almost?) no good reason to do that. 95 | * If you want to do something very custom, the Docker Toolbox is probably better anyway. 96 | 97 | 98 | # Using the Docker Toolbox 99 | 100 | The Docker Toolbox installs the following components: 101 | 102 | * VirtualBox + Boot2Docker VM image (runs Docker Engine) 103 | * Kitematic GUI 104 | * Docker CLI 105 | * Docker Machine 106 | * Docker Compose 107 | * A handful of clever wrappers 108 | 109 | 110 | # About boot2docker 111 | 112 | It is a very small VM image (~30 MB). 113 | 114 | It runs on most hypervisors and can also boot on actual hardware. 115 | 116 | Boot2Docker is not a "lite" version of Docker. 117 | 118 | ![Boot2Docker](logo.png) 119 | 120 | 121 | # Docker Mac and Docker Windows 122 | 123 | * Docker Mac and Docker Windows are newer products 124 | * They let you run Docker without VirtualBox 125 | * They are installed like normal applications (think QEMU, but faster) 126 | * They provide better integration with enterprise VPNs 127 | * They support filesystem sharing through volumes (we'll talk about this later) 128 | 129 | Only downside (for now): only one instance at a time; so if you want 130 | to run a full cluster on your local machine, you can fallback on the 131 | Docker Toolbox (it can coexist with Docker Mac/Windows just fine). 132 | 133 | 134 | # Su-su-sudo 135 | 136 | ![su-su-sudo](sudo.png) 137 | 138 | 139 | # Important PSA about security 140 | 141 | The ``docker`` user is ``root`` equivalent. 142 | 143 | It provides ``root``-level access to the host. 144 | 145 | You should restrict access to it like you would protect ``root``. 146 | 147 | If you give somebody the ability to access the Docker API, you are giving them full access on the machine. 148 | 149 | Therefore, the Docker control socket is (by default) owned by the `docker` group, to avoid unauthorized access on multi-user machines. 150 | 151 | If your user is not in the `docker` group, you will need to prefix every command with `sudo`; e.g. `sudo docker version`. 152 | 153 | 154 | # Reminder ... 155 | 156 | *Note:* if you were provided with a training VM for a hands-on 157 | tutorial, you can skip this chapter, since that VM already 158 | has Docker installed, and Docker has already been setup to run 159 | without ``sudo``. 160 | 161 | 162 | # The ``docker`` group 163 | 164 | ## Add the Docker group 165 | 166 | @@@ Sh 167 | $ sudo groupadd docker 168 | 169 | ## Add ourselves to the group 170 | 171 | @@@ Sh 172 | $ sudo gpasswd -a $USER docker 173 | 174 | ## Restart the Docker daemon 175 | 176 | @@@ Sh 177 | $ sudo service docker restart 178 | 179 | ## Log out 180 | 181 | @@@ Sh 182 | $ exit 183 | 184 | 185 | # Check that Docker works without sudo 186 | 187 | @@@ Sh 188 | $ docker version 189 | Client: 190 | Version: 1.11.1 191 | API version: 1.23 192 | Go version: go1.5.4 193 | Git commit: 5604cbe 194 | Built: Tue Apr 26 23:38:55 2016 195 | OS/Arch: linux/amd64 196 | 197 | Server: 198 | Version: 1.11.1 199 | API version: 1.23 200 | Go version: go1.5.4 201 | Git commit: 5604cbe 202 | Built: Tue Apr 26 23:38:55 2016 203 | OS/Arch: linux/amd64 204 | 205 | 206 | 207 | # Section summary 208 | 209 | We've learned how to: 210 | 211 | * Install Docker. 212 | * Run Docker without ``sudo``. 213 | 214 | 215 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Install Docker 216 | 217 | 1. We've already installed Docker inside our lab environment. 218 | 219 | 2. Connect to the lab environment. 220 | 221 | 222 | 223 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Stop, start and restart the Docker daemon 224 | 225 | We're going to use the ``service`` command to stop, start and restart 226 | the Docker daemon. 227 | 228 | 1. Stop the Docker daemon. 229 | 230 | @@@ Sh 231 | $ service docker stop 232 | 233 | 2. Start the Docker daemon. 234 | 235 | @@@ Sh 236 | $ service docker start 237 | 238 | 3. Restart the Docker daemon. 239 | 240 | @@@ Sh 241 | $ service docker restart 242 | 243 | 244 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Test the Docker client 245 | 246 | 1. Use the ``docker`` client to confirm the Docker daemon is running. 247 | 248 | @@@ Sh 249 | $ docker version 250 | 251 | 2. You should see: 252 | 253 | @@@ Sh 254 | Client version: 1.5.0 255 | Client API version: 1.17 256 | Go version (client): go1.4.1 257 | Git commit (client): a8a31ef 258 | OS/Arch (client): linux/amd64 259 | Server version: 1.5.0 260 | Server API version: 1.17 261 | Go version (server): go1.4.1 262 | Git commit (server): a8a31ef 263 | 264 | 265 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: See the Docker client help 266 | 267 | 1. Use the ``docker help`` command to see what the Docker client can do. 268 | 269 | @@@ Sh 270 | $ docker help 271 | 272 | 2. You should see: 273 | 274 | @@@ Sh 275 | Usage: docker [OPTIONS] COMMAND [arg...] 276 | -H=[unix:///var/run/docker.sock]: tcp://host:port to bind/connect to or unix://path/to/socket to use 277 | 278 | A self-sufficient runtime for linux containers. 279 | 280 | Commands: 281 | attach Attach to a running container 282 | build Build a container from a Dockerfile 283 | . . . 284 | 285 | 286 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Don't need no sudo 287 | 288 | 1. Create the ``docker`` group. 289 | 290 | @@@ Sh 291 | $ sudo groupadd docker 292 | 293 | 2. Add your user to the ``docker`` group. 294 | 295 | @@@ Sh 296 | $ sudo gpasswd -a $USER docker 297 | 298 | 3. Restart the Docker daemon. 299 | 300 | @@@ Sh 301 | $ sudo service docker restart 302 | 303 | 4. Log out. 304 | 305 | @@@ Sh 306 | $ exit 307 | 308 | 5. Login. 309 | 310 | @@@ Sh 311 | $ ssh ec2-user@yourlabhost 312 | you@ip.com's password: 313 | 314 | 6. Test that Docker works without ``sudo`` 315 | 316 | @@@ Sh 317 | $ docker version 318 | -------------------------------------------------------------------------------- /slides/Install_Docker/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Install Docker 3 | 4 | ![install](install.jpg) 5 | -------------------------------------------------------------------------------- /slides/Install_Docker/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Installing Docker 3 | 4 | ## Objectives 5 | 6 | At the end of this lesson, you will know: 7 | 8 | * How to install Docker. 9 | * When to use `sudo` when running Docker commands. 10 | 11 | *Note:* if you were provided with a training VM for a hands-on 12 | tutorial, you can skip this chapter, since that VM already 13 | has Docker installed, and Docker has already been setup to run 14 | without ``sudo``. 15 | -------------------------------------------------------------------------------- /slides/Install_Docker/install.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Install_Docker/install.jpg -------------------------------------------------------------------------------- /slides/Install_Docker/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Install_Docker/logo.png -------------------------------------------------------------------------------- /slides/Install_Docker/sudo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Install_Docker/sudo.png -------------------------------------------------------------------------------- /slides/Local_Development_Workflow/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # Using a Docker container for local development 3 | 4 | Never again: 5 | 6 | - "Works on my machine" 7 | - "Not the same version" 8 | - "Missing dependency" 9 | 10 | By using Docker containers, we will get a consistent development environment. 11 | 12 | 13 | # Our "namer" application 14 | 15 | * The code is available on https://github.com/jpetazzo/namer. 16 | * The image jpetazzo/namer is automatically built by the Docker Hub. 17 | 18 | Let's run it with: 19 | 20 | @@@ Sh 21 | $ docker run -dP jpetazzo/namer 22 | 23 | Check the port number with `docker ps` and open the application. 24 | 25 | 26 | 27 | # Let's look at the code 28 | 29 | Let's download our application's source code. 30 | 31 | @@@ Sh 32 | $ git clone https://github.com/jpetazzo/namer 33 | $ cd namer 34 | $ ls -1 35 | company_name_generator.rb 36 | config.ru 37 | docker-compose.yml 38 | Dockerfile 39 | Gemfile 40 | 41 | 42 | # Where's my code? 43 | 44 | According to the Dockerfile, the code is copied into `/src` : 45 | 46 | FROM ruby 47 | MAINTAINER Education Team at Docker 48 | 49 | COPY . /src 50 | WORKDIR /src 51 | RUN bundler install 52 | 53 | CMD ["rackup", "--host", "0.0.0.0"] 54 | EXPOSE 9292 55 | 56 | We want to make changes *inside the container* without rebuilding it each time. 57 | 58 | For that, we will use a *volume*. 59 | 60 | 61 | # Our first volume 62 | 63 | We will tell Docker to map the current directory to `/src` in the container. 64 | 65 | @@@ Sh 66 | $ docker run -d -v $(pwd):/src -p 80:9292 jpetazzo/namer 67 | 68 | * The ``-d`` flag indicates that the container should run in detached mode (in the background). 69 | * The ``-v`` flag provides volume mounting inside containers. 70 | * The ``-p`` flag maps port ``9292`` inside the container to port ``80`` on the host. 71 | * ``jpetazzo/namer`` is the name of the image we will run. 72 | * We don't need to give a command to run because the Dockerfile already specifies `rackup`. 73 | 74 | 75 | # Mounting volumes inside containers 76 | 77 | The ``-v`` flag mounts a directory from your host into your Docker 78 | container. The flag structure is: 79 | 80 | @@@ Sh 81 | [host-path]:[container-path]:[rw|ro] 82 | 83 | * If [host-path] or [container-path] doesn't exist it is created. 84 | * You can control the write status of the volume with the ``ro`` and 85 | ``rw`` options. 86 | * If you don't specify ``rw`` or ``ro``, it will be ``rw`` by default. 87 | 88 | There will be a full chapter about volumes! 89 | 90 | 91 | # Testing the development container 92 | 93 | Now let us see if our new container is running. 94 | 95 | @@@ Sh 96 | $ docker ps 97 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 98 | 045885b68bc5 trai... rackup 3 seconds ago Up ... 0.0.0.0:80->9292/tcp ... 99 | 100 | 101 | # Viewing our application 102 | 103 | Now let's browse to our web application on: 104 | 105 | @@@ Sh 106 | http://:80 107 | 108 | We can see our company naming application. 109 | 110 | ![web application 1](webapp1.png) 111 | 112 | 113 | # Making a change to our application 114 | 115 | Our customer really doesn't like the color of our text. Let's change it. 116 | 117 | @@@ Sh 118 | $ vi company_name_generator.rb 119 | 120 | And change 121 | 122 | @@@ CSS 123 | color: royalblue; 124 | 125 | To: 126 | 127 | @@@ CSS 128 | color: red; 129 | 130 | 131 | # Refreshing our application 132 | 133 | Now let's refresh our browser: 134 | 135 | @@@ Sh 136 | http://:80 137 | 138 | We can see the updated color of our company naming application. 139 | 140 | ![web application 2](webapp2.png) 141 | 142 | 143 | # Improving the workflow with Compose 144 | 145 | * You can also start the container with the following command: 146 | 147 | @@@ Sh 148 | $ docker-compose up -d 149 | 150 | * This works thanks to the Compose file, `docker-compose.yml`: 151 | 152 | @@@ YAML 153 | www: 154 | build: . 155 | volumes: 156 | - .:/src 157 | ports: 158 | - 80:9292 159 | 160 | 161 | # Why Compose? 162 | 163 | * Specifying all those "docker run" parameters is tedious. 164 | * And error-prone. 165 | * We can "encode" those parameters in a "Compose file." 166 | * When you see a `docker-compose.yml` file, you know that you can use `docker-compose up`. 167 | * Compose can also deal with complex, multi-container apps. 168 |
(More on this later.) 169 | 170 | 171 | # Workflow explained 172 | 173 | We can see a simple workflow: 174 | 175 | 1. Build an image containing our development environment. 176 | 177 | (Rails, Django...) 178 | 179 | 2. Start a container from that image. 180 | 181 | Use the ``-v`` flag to mount source code inside the container. 182 | 183 | 3. Edit source code outside the containers, using regular tools. 184 | 185 | (vim, emacs, textmate...) 186 | 187 | 4. Test application. 188 | 189 | (Some frameworks pick up changes automatically. 190 | 191 | Others require you to Ctrl-C + restart after each modification.) 192 | 193 | 5. Repeat last two steps until satisfied. 194 | 195 | 6. When done, commit+push source code changes. 196 | 197 | (You *are* using version control, right?) 198 | 199 | 200 | # Debugging inside the container 201 | 202 | In 1.3, Docker introduced a feature called `docker exec`. 203 | 204 | It allows users to run a new process in a container which is already running. 205 | 206 | If sometimes you find yourself wishing you could SSH into a container: you can use `docker exec` instead. 207 | 208 | You can get a shell prompt inside an existing container this way, or run an arbitrary process for automation. 209 | 210 | 211 | # ``docker exec`` example 212 | 213 | @@@ Sh 214 | $ # You can run ruby commands in the area the app is running and more! 215 | $ docker exec -it bash 216 | root@5ca27cf74c2e:/opt/namer# irb 217 | irb(main):001:0> [0, 1, 2, 3, 4].map {|x| x ** 2}.compact 218 | => [0, 1, 4, 9, 16] 219 | irb(main):002:0> exit 220 | 221 | 222 | # Stopping the container 223 | 224 | Now that we're done let's stop our container. 225 | 226 | @@@ Sh 227 | $ docker stop 228 | 229 | And remove it. 230 | 231 | @@@ Sh 232 | $ docker rm 233 | 234 | 235 | # Section summary 236 | 237 | We've learned how to: 238 | 239 | * Share code between container and host. 240 | * Set our working directory. 241 | * Use a simple local development workflow. 242 | 243 | -------------------------------------------------------------------------------- /slides/Local_Development_Workflow/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Local Development Workflow with Docker 3 | 4 | ![construction](construction.jpg) 5 | -------------------------------------------------------------------------------- /slides/Local_Development_Workflow/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Local Development Workflow with Docker 3 | 4 | ## Objectives 5 | 6 | At the end of this lesson, you will be able to: 7 | 8 | * Share code between container and host. 9 | * Use a simple local development workflow. 10 | -------------------------------------------------------------------------------- /slides/Local_Development_Workflow/construction.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Local_Development_Workflow/construction.jpg -------------------------------------------------------------------------------- /slides/Local_Development_Workflow/webapp1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Local_Development_Workflow/webapp1.png -------------------------------------------------------------------------------- /slides/Local_Development_Workflow/webapp2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Local_Development_Workflow/webapp2.png -------------------------------------------------------------------------------- /slides/Naming_And_Inspecting/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # Naming our containers 3 | 4 | So far, we have referenced containers with their ID. 5 | 6 | We have copy-pasted the ID, or used a shortened prefix. 7 | 8 | But each container can also be referenced by its name. 9 | 10 | If a container is named `prod-db`, I can do: 11 | 12 | @@@ Sh 13 | $ docker logs prod-db 14 | $ docker stop prod-db 15 | etc. 16 | 17 | 18 | # Default names 19 | 20 | When we create a container, if we don't give a specific 21 | name, Docker will pick one for us. 22 | 23 | It will be the concatenation of: 24 | 25 | * A mood (furious, goofy, suspicious, boring...) 26 | * The name of a famous inventor (tesla, darwin, wozniak...) 27 | 28 | Examples: `happy_curie`, `clever_hopper`, `jovial_lovelace` ... 29 | 30 | 31 | # Specifying a name 32 | 33 | You can set the name of the container when you create it. 34 | 35 | @@@ Sh 36 | $ docker run --name ticktock jpetazzo/clock 37 | 38 | If you specify a name that already exists, Docker will refuse 39 | to create the container. 40 | 41 | This lets us enforce unicity of a given resource. 42 | 43 | 44 | # Renaming containers 45 | 46 | * You can rename containers with `docker rename`. 47 | 48 | * This allows you to "free up" a name without destroying the associated container. 49 | 50 | 51 | # Inspecting a container 52 | 53 | The `docker inspect` command will output a very detailed JSON map. 54 | 55 | @@@ Sh 56 | $ docker inspect 57 | [{ 58 | "AppArmorProfile": "", 59 | "Args": [], 60 | "Config": { 61 | "AttachStderr": true, 62 | "AttachStdin": false, 63 | "AttachStdout": true, 64 | "Cmd": [ 65 | "bash" 66 | ], 67 | "CpuShares": 0, 68 | ... 69 | 70 | There are multiple ways to consume that information. 71 | 72 | 73 | # Parsing JSON with the Shell 74 | 75 | * You *could* grep and cut or awk the output of `docker inspect`. 76 | * Please, don't. 77 | * It's painful. 78 | * If you really must parse JSON from the Shell, use JQ! 79 |
(It's great.) 80 | 81 | @@@ Sh 82 | $ docker inspect | jq . 83 | 84 | * We will see a better solution which doesn't require extra tools. 85 | 86 | 87 | # Using `--format` 88 | 89 | You can specify a format string, which will be parsed by 90 | Go's text/template package. 91 | 92 | @@@ Sh 93 | $ docker inspect --format '{{ json .Created }}' 94 | "2015-02-24T07:21:11.712240394Z" 95 | 96 | * The generic syntax is to wrap the expression with double curly braces. 97 | * The expression starts with a dot representing the JSON object. 98 | * Then each field or member can be accessed in dotted notation syntax. 99 | * The optional `json` keyword asks for valid JSON output. 100 |
(e.g. here it adds the surrounding double-quotes.) 101 | -------------------------------------------------------------------------------- /slides/Naming_And_Inspecting/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Naming and inspecting containers 3 | 4 | ![Markings on container door](containermarkings.jpg) 5 | -------------------------------------------------------------------------------- /slides/Naming_And_Inspecting/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Naming and inspecting containers 3 | 4 | ## Objectives 5 | 6 | In this lesson, we will learn about an important 7 | Docker concept: container *naming*. 8 | 9 | Naming allows us to: 10 | 11 | * Reference easily a container. 12 | * Ensure unicity of a specific container. 13 | 14 | We will also see the `inspect` command, which gives a lot of details about a container. -------------------------------------------------------------------------------- /slides/Naming_And_Inspecting/containermarkings.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Naming_And_Inspecting/containermarkings.jpg -------------------------------------------------------------------------------- /slides/Securing_With_TLS/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # Why should I care? 3 | 4 | * Docker does not have any access controls on its network API unless you use TLS! 5 | 6 | 7 | # What is TLS 8 | 9 | * TLS is Transport Layer Security. 10 | * The protocol that secures websites with `https` URLs. 11 | * Uses Public Key Cryptography to encrypt connections. 12 | * Keys are signed with Certificates which are maintained by a trusted party. 13 | * These Certificates indicate that a trusted party believes the server is who it says it is. 14 | * Each transaction is therefor encrypted *and* authenticated. 15 | 16 | 17 | # How Docker Uses TLS 18 | 19 | * Docker provides mechanisms to authenticate both the server the client to _each other_. 20 | * Provides strong authentication, authorization and encryption for any API connection over the network. 21 | * Client keys can be distributed to authorized clients 22 | 23 | 24 | # Environment Preparation 25 | 26 | * You need to make sure that OpenSSL version 1.0.1 is installed on your machine. 27 | * Make a directory for all of the files to reside. 28 | * Make sure that the directory is protected and backed up! 29 | * *Treat these files the same as a root password.* 30 | 31 | 32 | # Creating a Certificate Authority 33 | 34 | First, initialize the CA serial file and generate CA private and public 35 | keys: 36 | 37 | @@@ Sh 38 | $ echo 01 > ca.srl 39 | $ openssl genrsa -des3 -out ca-key.pem 2048 40 | $ openssl req -new -x509 -days 365 -key ca-key.pem -out ca.pem 41 | 42 | We will use the `ca.pem` file to sign all of the other keys later. 43 | 44 | 45 | # Create and Sign the Server Key 46 | Now that we have a CA, we can create a server key and certificate 47 | signing request. Make sure that `CN` matches the hostname you run the Docker daemon on: 48 | 49 | @@@ Sh 50 | $ openssl genrsa -des3 -out server-key.pem 2048 51 | $ openssl req -subj '/CN=****' -new -key server-key.pem -out server.csr 52 | $ openssl rsa -in server-key.pem -out server-key.pem 53 | 54 | Next we're going to sign the key with our CA: 55 | 56 | @@@ Sh 57 | $ openssl x509 -req -days 365 -in server.csr -CA ca.pem -CAkey ca-key.pem \ 58 | -out server-cert.pem 59 | 60 | 61 | # Create and Sign the Client Key 62 | 63 | @@@ Sh 64 | $ openssl genrsa -des3 -out client-key.pem 2048 65 | $ openssl req -subj '/CN=client' -new -key client-key.pem -out client.csr 66 | $ openssl rsa -in client-key.pem -out client-key.pem 67 | 68 | To make the key suitable for client authentication, create a extensions 69 | config file: 70 | 71 | @@@ Sh 72 | $ echo extendedKeyUsage = clientAuth > extfile.cnf 73 | 74 | Now sign the key: 75 | 76 | @@@ Sh 77 | $ openssl x509 -req -days 365 -in client.csr -CA ca.pem -CAkey ca-key.pem \ 78 | -out client-cert.pem -extfile extfile.cnf 79 | 80 | 81 | # Configuring the Docker Daemon for TLS 82 | 83 | * By default, Docker does not listen on the network at all. 84 | * To enable remote connections, use the `-H` flag. 85 | * The assigned port for Docker over TLS is `2376`. 86 | 87 | @@@ Sh 88 | $ sudo docker -d --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem -H=0.0.0.0:2376 89 | 90 | _Note: You will need to modify the startup scripts on your server for this to be permanent! The keys should be placed in a secure system directory, such as /etc/docker._ 91 | 92 | 93 | 94 | 95 | # Configuring the Docker Client for TLS 96 | 97 | If you want to secure your Docker client connections by default, you can move the key files 98 | to the `.docker` directory in your home directory. Set the `DOCKER_HOST` variable as well. 99 | 100 | @@@ Sh 101 | $ cp ca.pem ~/.docker/ca.pem 102 | $ cp client-cert.pem ~/.docker/cert.pem 103 | $ cp client-key.pem ~/.docker/key.pem 104 | $ export DOCKER_HOST=tcp://:2376 105 | 106 | Then you can run docker with the `--tlsverify` option. 107 | 108 | @@@ Sh 109 | $ docker --tlsverify ps 110 | 111 | 112 | # Section Summary 113 | 114 | We learned how to: 115 | 116 | * Create a TLS Certificate Authority 117 | * Create TLS Keys 118 | * Sign TLS Keys 119 | * Use these keys with Docker 120 | 121 | 122 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Set up a CA 123 | 124 | 1. Initalize the CA in an empty directory. 125 | 126 | @@@ Sh 127 | $ mkdir docker-ca 128 | $ chmod 0700 docker-ca 129 | $ cd docker-ca 130 | $ echo 01 > ca.srl 131 | $ openssl genrsa -des3 -out ca-key.pem 2048 132 | $ openssl req -new -x509 -days 365 -key ca-key.pem -out ca.pem 133 | 134 | 135 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Generate Server Key and Sign it 136 | 137 | 1. Generate the Server Key 138 | 139 | @@@ Sh 140 | $ openssl genrsa -des3 -out server-key.pem 2048 141 | $ openssl req -subj '/CN=****' -new -key server-key.pem -out server.csr 142 | $ openssl rsa -in server-key.pem -out server-key.pem 143 | 144 | 2. Sign the key with our CA: 145 | 146 | @@@ Sh 147 | $ openssl x509 -req -days 365 -in server.csr -CA ca.pem -CAkey ca-key.pem \ 148 | -out server-cert.pem 149 | 150 | 151 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Generate Client Key and Sign it 152 | 153 | 1. Generate the Client Key 154 | 155 | @@@ Sh 156 | $ openssl genrsa -des3 -out client-key.pem 2048 157 | $ openssl req -subj '/CN=client' -new -key client-key.pem -out client.csr 158 | $ openssl rsa -in client-key.pem -out client-key.pem 159 | 160 | 2. Create an extensions config file 161 | 162 | @@@ Sh 163 | $ echo extendedKeyUsage = clientAuth > extfile.cnf 164 | 165 | 3. Sign the key 166 | 167 | @@@ Sh 168 | $ openssl x509 -req -days 365 -in client.csr -CA ca.pem -CAkey ca-key.pem \ 169 | -out client-cert.pem -extfile extfile.cnf 170 | 171 | 172 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Change Docker startup options 173 | 174 | 1. Copy the keys from the `docker-ca` directory to `/etc/docker` 175 | 176 | @@@ Sh 177 | $ sudo mkdir /etc/docker 178 | $ sudo chown docker:docker /etc/docker 179 | $ sudo chmod 0700 /etc/docker 180 | $ sudo cp ~/docker-ca/{ca,server-key,server-cert}.pem /etc/docker 181 | 182 | 2. Edit the file `/etc/default/docker` 183 | 184 | @@@ Sh 185 | $ sudo nano /etc/default/docker 186 | 187 | 3. Change the line: 188 | 189 | @@@ Sh 190 | DOCKER_OPTS="-H tcp://127.0.0.1:4243 -H unix:///var/run/docker.sock" 191 | to 192 | 193 | @@@ Sh 194 | DOCKER_OPTS="-H tcp://127.0.0.1:2376 --tlsverify --tlscacert=/etc/docker/ca.pem --tlscert=/etc/docker/server-cert.pem --tlskey=/etc/docker/server-key.pem" 195 | 196 | and save the file. 197 | 198 | 4. Restart docker 199 | 200 | @@@ Sh 201 | $ sudo service docker restart 202 | 203 | 204 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: Set up the client and test. 205 | 206 | 1. Copy the keys into the `~/.docker` directory 207 | 208 | @@@ Sh 209 | $ mkdir ~/.docker 210 | $ cp ~/docker-ca/ca.pem ~/.docker 211 | $ cp ~/docker-ca/client-key.pem ~/.docker/key.pem 212 | $ cp ~/docker-ca/client-cert.pem ~/.docker/cert.pem 213 | 214 | 2. Test the connection 215 | 216 | @@@ Sh 217 | $ docker --tlsverify ps 218 | 219 | All done! 220 | -------------------------------------------------------------------------------- /slides/Securing_With_TLS/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Securing Docker with TLS -------------------------------------------------------------------------------- /slides/Securing_With_TLS/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Securing Docker with TLS 3 | 4 | ## Objectives 5 | 6 | At the end of this lesson, you will be able to: 7 | 8 | * Understand how Docker uses TLS to secure and authorize remote clients 9 | * Create a TLS Certificate Authority 10 | * Create TLS Keys 11 | * Sign TLS Keys 12 | * Use these keys with Docker 13 | -------------------------------------------------------------------------------- /slides/Security/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # What can we do with Docker API access? 3 | 4 | Someone who has access to the Docker API will have full root 5 | privileges on the Docker host. 6 | 7 | If you give root privileges to someone, assume that they can do 8 | *anything they like* on the host, including: 9 | 10 | * Accessing all data. 11 | * Changing all data. 12 | * Creating new user accounts and changing passwords. 13 | * Installing stealth rootkits. 14 | * Shutting down the machine. 15 | 16 | 17 | # Accessing the host filesystem 18 | 19 | To do that, we will use ``-v`` to expose the host filesystem 20 | inside a container: 21 | 22 | @@@ Sh 23 | $ docker run -v /:/hostfs ubuntu cat /hostfs/etc/passwd 24 | ...This shows the content of /etc/passwd on the host... 25 | 26 | If you want to explore freely the host filesystem: 27 | 28 | @@@ Sh 29 | $ docker run -it -v /:/hostfs -w /hostfs ubuntu bash 30 | 31 | 32 | # Modifying the host filesystem 33 | 34 | Volumes are read-write by default, so let's create a dummy file 35 | on the host filesystem: 36 | 37 | @@@ Sh 38 | $ docker run -it -v /:/hostfs ubuntu touch /hostfs/hi-there 39 | $ ls -l / 40 | ...You will see the hi-there file, created on the host... 41 | 42 | Note: if you are using boot2docker or a remote Docker host, 43 | you won't see the ``hi-there`` file. It will be in the 44 | boot2docker VM, or on the remote Docker host instead. 45 | 46 | 47 | # Privileged containers 48 | 49 | If you start a container with ``--privileged``, it will be able 50 | to access all devices and perform all operations. 51 | 52 | For instance, it will be able to access the whole kernel memory 53 | by reading (and even writing!) ``/dev/kcore``. 54 | 55 | A container could also be started with ``--net host`` and 56 | ``--privileged`` together, and be able to sniff all the traffic 57 | going in and out of the machine. 58 | 59 | 60 | # Other harmful operations 61 | 62 | We won't explain how to do this (because we don't want you 63 | to break your Docker machines), but with access to the Docker 64 | API, you can: 65 | 66 | * Add user accounts. 67 | * Change password of existing accounts. 68 | * Add SSH key authentication to existing accounts. 69 | * Insert kernel modules. 70 | * Run malicious processes and insert special kernel code to hide them. 71 | 72 | 73 | # What to do? 74 | 75 | * Do not expose the Docker API to the general public. 76 | * If you expose the Docker API, secure it with TLS certificates. 77 | * TLS certificates will be presented in the next section. 78 | * Make sure that your users are trained to not give away credentials. 79 | 80 | 81 | # Security of containers themselves 82 | 83 | * "Containers Do Not Contain!" 84 | * Containers themselves do not have security features. 85 | * Security is ensured by a number of other mechanisms. 86 | * We will now review some of those mechanisms. 87 | 88 | 89 | # Do not run processes as root 90 | 91 | * By default, Docker runs everything as root. 92 | * This is a security risk. 93 | * Docker might eventually drop root privileges automatically, 94 | but until then, you should specify ``USER`` in your Dockerfiles, 95 | or use ``su`` or ``sudo``. 96 | 97 | 98 | # Don't colocate security-sensitive containers 99 | 100 | * If a container contains security-sensitive information, 101 | put it on its own Docker host, without other containers. 102 | * Other containers (private development environments, 103 | non-sensitive applications...) can be put together. 104 | 105 | 106 | 107 | # Run AppArmor or SELinux 108 | 109 | * Both of these will provide you with an additional layer of protection if 110 | an attacker is able to gain elevated access. 111 | 112 | 113 | # Learn more about containers and security 114 | 115 | * Presentation given at LinuxCon 2014 (Chicago) 116 | 117 | http://www.slideshare.net/jpetazzo/docker-linux-containers-lxc-and-security 118 | -------------------------------------------------------------------------------- /slides/Security/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Security 3 | 4 | ![](hackers.jpg) -------------------------------------------------------------------------------- /slides/Security/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Security 3 | 4 | ## Objectives 5 | 6 | At the end of this lesson, you will know: 7 | 8 | * The security implications of exposing Docker's API 9 | * How to take basic steps to make containers more secure 10 | * Where to find more information on Docker security 11 | -------------------------------------------------------------------------------- /slides/Security/Summary.md: -------------------------------------------------------------------------------- 1 | 2 | # Section summary 3 | 4 | We have learned: 5 | 6 | * The security implications of exposing Docker's API 7 | * How to take basic steps to make containers more secure 8 | * Where to find more information on Docker security 9 | -------------------------------------------------------------------------------- /slides/Security/hackers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Security/hackers.jpg -------------------------------------------------------------------------------- /slides/Start_And_Attach/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # Background and foreground 3 | 4 | The distinction between foreground and background containers is arbitrary. 5 | 6 | From Docker's point of view, all containers are the same. 7 | 8 | All containers run the same way, whether there is a client attached to them or not. 9 | 10 | It is always possible to detach from a container, and to reattach to a container. 11 | 12 | Analogy: attaching to a container is like plugging a keyboard and screen to a physical server. 13 | 14 | 15 | # Detaching from a container 16 | 17 | * If you have started an *interactive* container (with option `-it`), 18 |
you can detach from it. 19 | * The "detach" sequence is `^P^Q`. 20 | * Otherwise you can detach by killing the Docker client. 21 |
(But not by hitting `^C`, as this would deliver `SIGINT` 22 | to the container.) 23 | 24 | What does `-it` stand for? 25 | 26 | * `-t` means "allocate a terminal." 27 | * `-i` means "connect stdin to the terminal." 28 | 29 | 30 | # Specifying a custom detach sequence 31 | 32 | * You don't like `^P^Q`? No problem! 33 | * You can change the sequence with `docker run --detach-keys`. 34 | * This can also be passed as a global option to the engine. 35 | 36 | Start a container with a custom detach command: 37 | 38 | @@@ Sh 39 | $ docker run -ti --detach-keys ctrl-x,x jpetazzo/clock 40 | 41 | Detach by hitting `^X x`. (This is ctrl-x then x, not ctrl-x twice!) 42 | 43 | Check that our container is still running: 44 | 45 | @@@ Sh 46 | $ docker ps -l 47 | 48 | 49 | # Attaching to a container 50 | 51 | You can attach to a container: 52 | 53 | @@@ Sh 54 | $ docker attach 55 | 56 | * The container must be running. 57 | * There *can* be multiple clients attached to the same container. 58 | * If you don't specify `--detach-keys` when attaching, it defaults back to `^P^Q`. 59 | 60 | Try it on our previous container: 61 | 62 | @@@ Sh 63 | $ docker attach $(docker ps -lq) 64 | 65 | Check that `^X x` doesn't work, but `^P ^Q` does. 66 | 67 | 68 | # Detaching from non-interactive containers 69 | 70 | * **Warning:** if the container was started without `-it`... 71 | 72 | * You won't be able to detach with `^P^Q`. 73 | * If you hit `^C`, the signal will be proxied to the container. 74 | 75 | * Remember: you can always detach by killing the Docker client. 76 | 77 | 78 | # Checking container output 79 | 80 | * Use `docker attach` if you intend to send input to the container. 81 | * If you just want to see the output of a container, use `docker logs`. 82 | 83 | @@@ Sh 84 | $ docker logs --tail 1 --follow 85 | 86 | 87 | # Restarting a container 88 | 89 | When a container has exited, it is in stopped state. 90 | 91 | It can then be restarted with the `start` command. 92 | 93 | @@@ Sh 94 | $ docker start 95 | 96 | The container will be restarted using the same options you launched it 97 | with. 98 | 99 | You can re-attach to it if you want to interact with it: 100 | 101 | @@@ Sh 102 | $ docker attach 103 | 104 | Use `docker ps -a` to identify the container ID of a previous `jpetazzo/clock` container, 105 | and try those commands. 106 | 107 | 108 | # Attaching to a REPL 109 | 110 | * REPL = Read Eval Print Loop 111 | * Shells, interpreters, TUI ... 112 | * Symptom: you `docker attach`, and see nothing 113 | * The REPL doesn't know that you just attached, and doesn't print anything 114 | * Try hitting `^L` or `Enter` 115 | 116 | 117 | # SIGWINCH 118 | 119 | * When you `docker attach`, the Docker Engine sends a couple of SIGWINCH signals to the container. 120 | * SIGWINCH = WINdow CHange; indicates a change in window size. 121 | * This will cause some CLI and TUI programs to redraw the screen. 122 | * But not all of them. 123 | -------------------------------------------------------------------------------- /slides/Start_And_Attach/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Restarting and Attaching to Containers 3 | -------------------------------------------------------------------------------- /slides/Start_And_Attach/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Restarting and Attaching to Containers 3 | 4 | ## Objectives 5 | 6 | We have started containers in the foreground, and in the background. 7 | 8 | In this chapter, we will see how to: 9 | 10 | * Put a container in the background. 11 | * Attach to a background container to bring it to the foreground. 12 | * Restart a stopped container. 13 | -------------------------------------------------------------------------------- /slides/Template/1_Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # TODO 3 | 4 | -------------------------------------------------------------------------------- /slides/Template/2_Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: TODO 3 | 4 | ## Objectives 5 | 6 | At the end of this lesson, you will be able to: 7 | 8 | * TODO 9 | 10 | -------------------------------------------------------------------------------- /slides/Template/3_Body.md: -------------------------------------------------------------------------------- 1 | 2 | # TODO 3 | 4 | TODO 5 | -------------------------------------------------------------------------------- /slides/Template/4_Exercises.md: -------------------------------------------------------------------------------- 1 | 2 | # Lab ~~~SECTION:MAJOR~~~.~~~SECTION:MINOR~~~: TODO 3 | 4 | 1. TODO 5 | 6 | -------------------------------------------------------------------------------- /slides/Template/5_Conclusion.md: -------------------------------------------------------------------------------- 1 | 2 | # Section summary 3 | 4 | We've learned how to: 5 | 6 | * TODO 7 | -------------------------------------------------------------------------------- /slides/Use_Training_VM/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # Your training Virtual Machine 3 | 4 | This section assumes that you are following this course as part of 5 | an official Docker training or workshop, and have been given credentials 6 | to connect to your own private Docker VM. 7 | 8 | This VM has been created specifically for you, just before the training. 9 | 10 | It comes pre-installed with the latest and shiniest version of Docker, 11 | as well as some useful tools. 12 | 13 | It will stay up and running for the whole training, but it will be destroyed 14 | shortly after the training. 15 | 16 | 17 | 18 | # Connecting to your Virtual Machine 19 | 20 | You need an SSH client. 21 | 22 | * On OS X, Linux, and other UNIX systems, just use `ssh`: 23 | 24 | @@@ Sh 25 | $ ssh @ 26 | 27 | * On Windows, if you don't have an SSH client, you can download: 28 | * Putty (www.putty.org) 29 | * Git BASH (https://git-for-windows.github.io/) 30 | * MobaXterm (http://moabaxterm.mobatek.net) 31 | 32 | 33 | 34 | # Checking your Virtual Machine 35 | 36 | Once logged in, make sure that you can run a basic Docker command: 37 | 38 | @@@ Sh 39 | $ docker version 40 | Client: 41 | Version: 1.11.1 42 | API version: 1.23 43 | Go version: go1.5.4 44 | Git commit: 5604cbe 45 | Built: Tue Apr 26 23:38:55 2016 46 | OS/Arch: linux/amd64 47 | 48 | Server: 49 | Version: 1.11.1 50 | API version: 1.23 51 | Go version: go1.5.4 52 | Git commit: 5604cbe 53 | Built: Tue Apr 26 23:38:55 2016 54 | OS/Arch: linux/amd64 55 | 56 | * If this doesn't work, raise your hand so that an instructor can assist you! 57 | -------------------------------------------------------------------------------- /slides/Use_Training_VM/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Your training Virtual Machine 3 | 4 | ![SSH terminal](ssh.jpg) 5 | -------------------------------------------------------------------------------- /slides/Use_Training_VM/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Your training Virtual Machine 3 | 4 | ## Objectives 5 | 6 | In this section, we will see how to use your training Virtual Machine. 7 | 8 | If you are following this course as part of an official Docker training 9 | or workshop, you have been given credentials to connect to your own 10 | private Docker VM. 11 | 12 | If you are following this course on your own, without access to an 13 | official training Virtual Machine, just skip this lesson, and check 14 | "Installing Docker" instead. -------------------------------------------------------------------------------- /slides/Use_Training_VM/install.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Use_Training_VM/install.jpg -------------------------------------------------------------------------------- /slides/Use_Training_VM/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Use_Training_VM/logo.png -------------------------------------------------------------------------------- /slides/Use_Training_VM/ssh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Use_Training_VM/ssh.jpg -------------------------------------------------------------------------------- /slides/Use_Training_VM/sudo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Use_Training_VM/sudo.png -------------------------------------------------------------------------------- /slides/Vulnerabilities/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # Vulnerabilities 3 | 4 | When a vulnerability is discovered, it is common practice for 5 | the vendor or community to issue a *security advisory*. 6 | 7 | The security advisory will typically indicate: 8 | 9 | * The affected software. 10 | * The specific scenarios (if relevant) where the vulnerability 11 | should be a concern. 12 | * The specific versions affected by the vulnerability. 13 | * The severity of the vulnerability (e.g. can it lead to malfunction, 14 | or prevent others from using the software or service, or allow 15 | unauthorized access or modification to data). 16 | * How to remediate it (typically by upgrading affected software). 17 | 18 | 19 | # Vulnerabilities in Docker 20 | 21 | The typical method to deal with Docker vulnerabilities is: 22 | 23 | * Stop all containers. 24 | * Stop the Docker daemon. 25 | * Upgrade the Docker daemon. 26 | * Start the Docker daemon. 27 | * Start the container. 28 | 29 | 30 | # Vulnerabilities in images 31 | 32 | If a vulnerability is announced concerning a package that you 33 | are using in your images, you should upgrade those images. 34 | 35 | Assuming that updated packages are available, you should: 36 | 37 | * Force a `docker pull` of all your base images. 38 | * Re-execute a `docker build --no-cache` of all your built images. 39 | * Re-start all containers using the updated images. 40 | 41 | 42 | # Detecting vulnerabilities 43 | 44 | You can use traditional auditing systems, but Docker provides 45 | new, efficient, non-intrusive ways to perform security audit 46 | and vulnerability reporting. 47 | 48 | The use of the `--read-only` flag lets you perform offline 49 | analysis of images to detect those which have vulnerable software. -------------------------------------------------------------------------------- /slides/Vulnerabilities/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Dealing with Vulnerabilities 3 | 4 | ![](security-breach.jpg) -------------------------------------------------------------------------------- /slides/Vulnerabilities/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Dealing with Vulnerabilities 3 | 4 | ## Objectives 5 | 6 | We will discuss how to address security vulnerabilities disclosures: 7 | 8 | * Concerning Docker itself. 9 | * Concerning the dependencies pulled into your container images. 10 | -------------------------------------------------------------------------------- /slides/Vulnerabilities/security-breach.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Vulnerabilities/security-breach.jpg -------------------------------------------------------------------------------- /slides/Working_With_Volumes/Body.md: -------------------------------------------------------------------------------- 1 | 2 | # Working with Volumes 3 | 4 | Docker volumes can be used to achieve many things, including: 5 | 6 | * Bypassing the copy-on-write system to obtain native disk I/O performance. 7 | * Bypassing copy-on-write to leave some files out of ``docker commit``. 8 | * Sharing a directory between multiple containers. 9 | * Sharing a directory between the host and a container. 10 | * Sharing a *single file* between the host and a container. 11 | 12 | 13 | # Volumes are special directories in a container 14 | 15 | Volumes can be declared in two different ways. 16 | 17 | * Within a ``Dockerfile``, with a ``VOLUME`` instruction. 18 | 19 | @@@ docker 20 | VOLUME /uploads 21 | 22 | * On the command-line, with the ``-v`` flag for ``docker run``. 23 | 24 | @@@ Sh 25 | $ docker run -d -v /uploads myapp 26 | 27 | In both cases, ``/uploads`` (inside the container) will be a volume. 28 | 29 | 30 | # Volumes bypass the copy-on-write system 31 | 32 | Volumes act as passthroughs to the host filesystem. 33 | 34 | * The I/O performance on a volume is exactly the same as I/O performance 35 | on the Docker host. 36 | * When you ``docker commit``, the content of volumes is not brought into 37 | the resulting image. 38 | * If a ``RUN`` instruction in a ``Dockerfile`` changes the content of a 39 | volume, those changes are not recorded neither. 40 | * If a container is started with the ``--read-only`` flag, the volume 41 | will still be writable (unless the volume is a read-only volume). 42 | 43 | 44 | # Volumes can be shared across containers 45 | 46 | You can start a container with *exactly the same volumes* as another one. 47 | 48 | The new container will have the same volumes, in the same directories. 49 | 50 | They will contain exactly the same thing, and remain in sync. 51 | 52 | Under the hood, they are actually the same directories on the host anyway. 53 | 54 | This is done using the ``--volumes-from`` flag for ``docker run``. 55 | 56 | @@@ Sh 57 | $ docker run -it --name alpha -v /var/log ubuntu bash 58 | root@99020f87e695:/# date >/var/log/now 59 | 60 | In another terminal, let's start another container with the same volume. 61 | 62 | @@@ Sh 63 | $ docker run --volumes-from alpha ubuntu cat /var/log/now 64 | Fri May 30 05:06:27 UTC 2014 65 | 66 | 67 | # Volumes exist independently of containers 68 | 69 | If a container is stopped, its volumes still exist and are available. 70 | 71 | Since Docker 1.9, we can see all existing volumes and manipulate them: 72 | 73 | @@@ Sh 74 | $ docker volume ls 75 | DRIVER VOLUME NAME 76 | local 5b0b65e4316da67c2d471086640e6005ca2264f3... 77 | local pgdata-prod 78 | local pgdata-dev 79 | local 13b59c9936d78d109d094693446e174e5480d973... 80 | 81 | Some of those volume names were explicit (pgdata-prod, pgdata-dev). 82 | 83 | The others (the hex IDs) were generated automatically by Docker. 84 | 85 | 86 | 87 | # Data containers (before Engine 1.9) 88 | 89 | A *data container* is a container created for the sole purpose of referencing 90 | one (or many) volumes. 91 | 92 | It is typically created with a no-op command: 93 | 94 | @@@ Sh 95 | $ docker run --name files -v /var/www busybox true 96 | $ docker run --name logs -v /var/log busybox true 97 | 98 | * We created two data containers. 99 | * They are using the ``busybox`` image, a tiny image. 100 | * We used the command ``true``, possibly the simplest command in the world! 101 | * We named each container to reference them easily later. 102 | 103 | 104 | # Using data containers 105 | 106 | Data containers are used by other containers thanks to ``--volumes-from``. 107 | 108 | Consider the following (fictitious) example, using the previously created volumes: 109 | 110 | @@@ Sh 111 | $ docker run -d --volumes-from files --volumes-from logs webserver 112 | $ docker run -d --volumes-from files ftpserver 113 | $ docker run -d --volumes-from logs lumberjack 114 | 115 | * The first container runs a webserver, serving content from ``/var/www`` 116 | and logging to ``/var/log``. 117 | * The second container runs a FTP server, allowing to upload content to the 118 | same ``/var/www`` path. 119 | * The third container collects the logs, and sends them to logstash, a log 120 | storage and analysis system, using the lumberjack protocol. 121 | 122 | 123 | # Named volumes (since Engine 1.9) 124 | 125 | * We can now create and manipulate volumes as first-class concepts. 126 | * Volumes can be created without a container, then used in multiple containers. 127 | 128 | Let's create a volume directly. 129 | 130 | @@@ Sh 131 | $ docker volume create --name=website 132 | website 133 | 134 | Volumes are not anchored to a specific path. 135 | 136 | 137 | # Using our named volumes 138 | 139 | * Volumes are used with the `-v` option. 140 | * When a host path does not contain a /, it is considered to be a volume name. 141 | 142 | Let's start a web server using the two previous volumes. 143 | 144 | @@@ Sh 145 | $ docker run -d -p 8888:80 \ 146 | -v website:/usr/share/nginx/html \ 147 | -v logs:/var/log/nginx \ 148 | nginx 149 | 150 | Check that it's running correctly: 151 | 152 | @@@ Sh 153 | $ curl localhost:8888 154 | 155 | ... 156 |

Welcome to nginx!

157 | ... 158 | 159 | 160 | # Using a volume in another container 161 | 162 | * We will make changes to the volume from another container. 163 | * In this example, we will run a text editor in the other container, but this could be a FTP server, a WebDAV server, a Git receiver... 164 | 165 | Let's start another container using the `website` volume. 166 | 167 | @@@ Sh 168 | $ docker run -v website:/website -w /website -ti alpine vi index.html 169 | 170 | Make changes, save, and exit. 171 | 172 | Then run `curl localhost:8888` again to see your changes. 173 | 174 | 175 | 176 | # Managing volumes explicitly 177 | 178 | In some cases, you want a specific directory on the host to be mapped 179 | inside the container: 180 | 181 | * You want to manage storage and snapshots yourself. 182 | 183 | (With LVM, or a SAN, or ZFS, or anything else!) 184 | 185 | * You have a separate disk with better performance (SSD) or resiliency (EBS) 186 | than the system disk, and you want to put important data on that disk. 187 | 188 | * You want to share your source directory between your host (where the 189 | source gets edited) and the container (where it is compiled or executed). 190 | 191 | Wait, we already met the last use-case in our example development workflow! 192 | Nice. 193 | 194 | @@@ Sh 195 | $ docker run -d -v /path/on/the/host:/path/in/container image ... 196 | 197 | 198 | 199 | # Sharing a directory between the host and a container 200 | 201 | The previous example would become something like this: 202 | 203 | @@@ Sh 204 | $ mkdir -p /mnt/files /mnt/logs 205 | $ docker run -d -v /mnt/files:/var/www -v /mnt/logs:/var/log webserver 206 | $ docker run -d -v /mnt/files:/home/ftp ftpserver 207 | $ docker run -d -v /mnt/logs:/var/log lumberjack 208 | 209 | Note that the paths must be absolute. 210 | 211 | Those volumes can also be shared with ``--volumes-from``. 212 | 213 | 214 | # Migrating data with `--volumes-from` 215 | 216 | The `--volumes-from` option tells Docker to re-use all the volumes 217 | of an existing container. 218 | 219 | * Scenario: migrating from Redis 2.8 to Redis 3.0. 220 | * We have a container (`myredis`) running Redis 2.8. 221 | * Stop the `myredis` container. 222 | * Start a new container, using the Redis 3.0 image, and the `--volumes-from` option. 223 | * The new container will inherit the data of the old one. 224 | * Newer containers can use `--volumes-from` too. 225 | 226 | 227 | # Data migration in practice 228 | 229 | Let's create a Redis container. 230 | 231 | @@@ Sh 232 | $ docker run -d --name redis28 redis:2.8 233 | 234 | Connect to the Redis container and set some data. 235 | 236 | @@@ Sh 237 | $ docker run -ti --link redis28:redis alpine telnet redis 6379 238 | 239 | Issue the following commands: 240 | 241 | @@@ Sh 242 | SET counter 42 243 | INFO server 244 | SAVE 245 | QUIT 246 | 247 | 248 | # Upgrading Redis 249 | 250 | Stop the Redis container. 251 | 252 | @@@ Sh 253 | $ docker stop redis28 254 | 255 | Start the new Redis container. 256 | 257 | @@@ Sh 258 | $ docker run -d --name redis30 --volumes-from redis28 redis:3.0 259 | 260 | 261 | # Testing the new Redis 262 | 263 | Connect to the Redis container and see our data. 264 | 265 | @@@ Sh 266 | docker run -ti --link redis30:redis alpine telnet redis 6379 267 | 268 | Issue a few commands. 269 | 270 | @@@ Sh 271 | GET counter 272 | INFO server 273 | QUIT 274 | 275 | 276 | # What happens when you remove containers with volumes? 277 | 278 | * With Engine versions prior 1.9, volumes would be *orphaned* when the last container referencing them is destroyed. 279 | * Orphaned volumes are not deleted, but you cannot access them. 280 | 281 | (Unless you do some serious archaeology in `/var/lib/docker`.) 282 | 283 | * Since Engine 1.9, orphaned volumes can be listed with `docker volume ls` and mounted to containers with `-v`. 284 | 285 | Ultimately, _you_ are the one responsible for logging, 286 | monitoring, and backup of your volumes. 287 | 288 | 289 | # Checking volumes defined by an image 290 | 291 | Wondering if an image has volumes? Just use ``docker inspect``: 292 | 293 | @@@ Sh 294 | $ # docker inspect training/datavol 295 | [{ 296 | "config": { 297 | . . . 298 | "Volumes": { 299 | "/var/webapp": {} 300 | }, 301 | . . . 302 | }] 303 | 304 | 305 | # Checking volumes used by a container 306 | 307 | To look which paths are actually volumes, and to what they are bound, 308 | use ``docker inspect`` (again): 309 | 310 | @@@ Sh 311 | $ docker inspect 312 | [{ 313 | "ID": "", 314 | . . . 315 | "Volumes": { 316 | "/var/webapp": "/var/lib/docker/vfs/dir/f4280c5b6207ed531efd4cc673ff620cef2a7980f747dbbcca001db61de04468" 317 | }, 318 | "VolumesRW": { 319 | "/var/webapp": true 320 | }, 321 | }] 322 | 323 | * We can see that our volume is present on the file system of the Docker host. 324 | 325 | 326 | # Sharing a single file between the host and a container 327 | 328 | The same ``-v`` flag can be used to share a single file. 329 | 330 | One of the most interesting examples is to share the Docker control socket. 331 | 332 | @@@ Sh 333 | $ docker run -it -v /var/run/docker.sock:/var/run/docker.sock docker sh 334 | 335 | Warning: when using such mounts, the container gains root-like access to the host. 336 | It can potentially do bad things. 337 | 338 | 339 | # Volume plugins 340 | 341 | You can install plugins to manage volumes backed by particular storage systems, 342 | or providing extra features. For instance: 343 | 344 | * [dvol](https://github.com/ClusterHQ/dvol) - allows to commit/branch/rollback volumes; 345 | * [Flocker](https://clusterhq.com/flocker/introduction/), [REX-Ray](https://github.com/emccode/rexray) - create and manage volumes backed by an enterprise storage system (e.g. SAN or NAS), or by cloud block stores (e.g. EBS); 346 | * [Blockbridge](http://www.blockbridge.com/), [Portworx](http://portworx.com/) - provide distributed block store for containers; 347 | * and much more! 348 | 349 | 350 | # Section summary 351 | 352 | We've learned how to: 353 | 354 | * Create and manage volumes. 355 | * Share volumes across containers. 356 | * Share a host directory with one or many containers. 357 | 358 | -------------------------------------------------------------------------------- /slides/Working_With_Volumes/Cover.md: -------------------------------------------------------------------------------- 1 | 2 | # Working with Volumes 3 | 4 | ![volume](volume.jpg) 5 | -------------------------------------------------------------------------------- /slides/Working_With_Volumes/Objectives.md: -------------------------------------------------------------------------------- 1 | 2 | # Lesson ~~~SECTION:MAJOR~~~: Working with Volumes 3 | 4 | ## Objectives 5 | 6 | At the end of this lesson, you will be able to: 7 | 8 | * Create containers holding volumes. 9 | * Share volumes across containers. 10 | * Share a host directory with one or many containers. 11 | -------------------------------------------------------------------------------- /slides/Working_With_Volumes/volume.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/Working_With_Volumes/volume.jpg -------------------------------------------------------------------------------- /slides/_images/DockerLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/_images/DockerLogo.png -------------------------------------------------------------------------------- /slides/_images/exercise-sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/_images/exercise-sm.png -------------------------------------------------------------------------------- /slides/_images/exercise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/_images/exercise.png -------------------------------------------------------------------------------- /slides/_images/lab-sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/_images/lab-sm.png -------------------------------------------------------------------------------- /slides/_images/lab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/_images/lab.png -------------------------------------------------------------------------------- /slides/_images/linen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/_images/linen.png -------------------------------------------------------------------------------- /slides/_preshow/DockerLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/_preshow/DockerLogo.png -------------------------------------------------------------------------------- /slides/_preshow/README: -------------------------------------------------------------------------------- 1 | Place any images you'd like in this folder and they will be displayed any time 2 | you take a break, or before class, etc. If you'd like to put titles on the 3 | images, you can use the below text to create a `preshow.json` file. 4 | 5 | { 6 | "DockerLogo.png":"Docker Fundamentals", 7 | } 8 | 9 | -------------------------------------------------------------------------------- /slides/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/favicon.ico -------------------------------------------------------------------------------- /slides/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpetazzo/intro-to-docker/898db79e423711d98987e461090a7db9612a100e/slides/favicon.png -------------------------------------------------------------------------------- /slides/fonts.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Cabin'; 3 | font-style: normal; 4 | font-weight: 400; 5 | src: local('Cabin Regular'), local('Cabin-Regular'), url(http://themes.googleusercontent.com/static/fonts/cabin/v5/kJXt72Gt1LyFMZcEKAAvlKCWcynf_cDxXwCLxiixG1c.woff) format('woff'); 6 | } 7 | @font-face { 8 | font-family: 'Cabin'; 9 | font-style: normal; 10 | font-weight: 700; 11 | src: local('Cabin Bold'), local('Cabin-Bold'), url(http://themes.googleusercontent.com/static/fonts/cabin/v5/haOjnueK8Or1ztuuRtr8dnYhjbSpvc47ee6xR_80Hnw.woff) format('woff'); 12 | } 13 | @font-face { 14 | font-family: 'Cabin'; 15 | font-style: italic; 16 | font-weight: 400; 17 | src: local('Cabin Italic'), local('Cabin-Italic'), url(http://themes.googleusercontent.com/static/fonts/cabin/v5/SYYqINfDCIH45kObNrBWvgLUuEpTyoUstqEm5AMlJo4.woff) format('woff'); 18 | } 19 | -------------------------------------------------------------------------------- /slides/print.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Docker Fundamentals {{DOCKER_TRAINING_VERSION}}", 3 | "description": "Docker Fundamentals Course Materials, revision {{DOCKER_TRAINING_VERSION}}", 4 | "protected": ["presenter", "onepage"], 5 | "user": "docker", 6 | "password": "maersk", 7 | "sections": [ 8 | 9 | "Course_Overview/Course_Intro.md", 10 | "Course_Overview/Table_of_contents.md", 11 | "Course_Overview/Course_Objectives.md", 12 | "Course_Overview/Course_Overview.md", 13 | "Course_Overview/Course_Agenda_1.md", 14 | 15 | "About_Docker/Section.md", 16 | "About_Docker/Objectives.md", 17 | "About_Docker/About_Docker.md", 18 | "About_Docker/Current_State.md", 19 | "About_Docker/Introducing_Docker.md", 20 | "About_Docker/Resources.md", 21 | "About_Docker/How_Docker_Works.md", 22 | 23 | "Concepts/Section.md", 24 | "Concepts/Objectives.md", 25 | 26 | "Classroom_Setup/Section.md", 27 | "Classroom_Setup/Objectives.md", 28 | 29 | "Course_Conclusion/Conclusion_Section.md", 30 | "Course_Conclusion/Course_Summary.md", 31 | "Course_Conclusion/next_steps.md", 32 | 33 | "Appendix/Section.md" 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /slides/showoff.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Introduction to Docker", 3 | "description": "Introduction to Docker Course Materials", 4 | "training_version": "{{DOCKER_TRAINING_VERSION}}", 5 | "protected": ["presenter", "onepage"], 6 | "user": "docker", 7 | "password": "maersk", 8 | "issues": "https://github.com/docker-training/docker-fundamentals", 9 | "favicon": "https://www.docker.io/static/favicon.png", 10 | "sections": [ 11 | 12 | "Course_Overview/Cover.md", 13 | "Course_Overview/Intro.md", 14 | "Course_Overview/Toc.md", 15 | 16 | "About_Docker/Cover.md", 17 | "About_Docker/Objectives.md", 18 | "About_Docker/Body.md", 19 | 20 | "Use_Training_VM/Cover.md", 21 | "Use_Training_VM/Objectives.md", 22 | "Use_Training_VM/Body.md", 23 | 24 | "Install_Docker/Cover.md", 25 | "Install_Docker/Objectives.md", 26 | "Install_Docker/Body.md", 27 | 28 | "First_Containers/Cover.md", 29 | "First_Containers/Objectives.md", 30 | "First_Containers/Body.md", 31 | 32 | "Background_Containers/Cover.md", 33 | "Background_Containers/Objectives.md", 34 | "Background_Containers/Body.md", 35 | 36 | "Start_And_Attach/Cover.md", 37 | "Start_And_Attach/Objectives.md", 38 | "Start_And_Attach/Body.md", 39 | 40 | "Initial_Images/Cover.md", 41 | "Initial_Images/Objectives.md", 42 | "Initial_Images/Body.md", 43 | 44 | "Building_Images_Interactively/Cover.md", 45 | "Building_Images_Interactively/Objectives.md", 46 | "Building_Images_Interactively/Body.md", 47 | 48 | "Building_Images_With_Dockerfiles/Cover.md", 49 | "Building_Images_With_Dockerfiles/Objectives.md", 50 | "Building_Images_With_Dockerfiles/Body.md", 51 | 52 | "Cmd_And_Entrypoint/Cover.md", 53 | "Cmd_And_Entrypoint/Objectives.md", 54 | "Cmd_And_Entrypoint/Body.md", 55 | 56 | "Copying_Files_During_Build/Cover.md", 57 | "Copying_Files_During_Build/Objectives.md", 58 | "Copying_Files_During_Build/Body.md", 59 | 60 | "Dockerfile_Reference/Cover.md", 61 | "Dockerfile_Reference/Objectives.md", 62 | "Dockerfile_Reference/Body.md", 63 | 64 | "Docker_Hub_Tease/Cover.md", 65 | "Docker_Hub_Tease/Objectives.md", 66 | "Docker_Hub_Tease/Body.md", 67 | 68 | "Naming_And_Inspecting/Cover.md", 69 | "Naming_And_Inspecting/Objectives.md", 70 | "Naming_And_Inspecting/Body.md", 71 | 72 | "Container_Networking_Basics/Cover.md", 73 | "Container_Networking_Basics/Objectives.md", 74 | "Container_Networking_Basics/Body.md", 75 | 76 | "Container_Network_Model/Cover.md", 77 | "Container_Network_Model/Objectives.md", 78 | "Container_Network_Model/Body.md", 79 | 80 | "Connecting_Containers_With_Links/Cover.md", 81 | "Connecting_Containers_With_Links/Objectives.md", 82 | "Connecting_Containers_With_Links/Body.md", 83 | 84 | "Ambassadors/Cover.md", 85 | "Ambassadors/Objectives.md", 86 | "Ambassadors/Body.md", 87 | 88 | "Local_Development_Workflow/Cover.md", 89 | "Local_Development_Workflow/Objectives.md", 90 | "Local_Development_Workflow/Body.md", 91 | 92 | "Working_With_Volumes/Cover.md", 93 | "Working_With_Volumes/Objectives.md", 94 | "Working_With_Volumes/Body.md", 95 | 96 | "Compose_For_Dev_Stacks/Cover.md", 97 | "Compose_For_Dev_Stacks/Objectives.md", 98 | "Compose_For_Dev_Stacks/Body.md", 99 | 100 | "Course_Conclusion/Cover.md", 101 | "Course_Conclusion/Body.md" 102 | ] 103 | } 104 | -------------------------------------------------------------------------------- /tools/README.md: -------------------------------------------------------------------------------- 1 | # Tools 2 | 3 | Hopefully useful tools for the training material and associated course. 4 | 5 | 6 | ## find-non-ascii-7-characters.sh 7 | 8 | Sometimes, showoff will crash if there are characters outside of the ASCII7 9 | character set. This script detects and shows those characters. 10 | 11 | 12 | ## make-toc.py 13 | 14 | Extract titles (to generate an outline to include in a conference submission 15 | or similar). 16 | 17 | 18 | ## Where are the VM tools? 19 | 20 | They have been rehauled and the new version is publicly available [here]( 21 | https://github.com/jpetazzo/orchestration-workshop/tree/master/prepare-vms). 22 | 23 | -------------------------------------------------------------------------------- /tools/edit-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd ../slides 3 | vi $(grep md showoff.json | grep -v // | cut -d\" -f2) 4 | -------------------------------------------------------------------------------- /tools/extract-section-titles.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import json 4 | import click 5 | """ 6 | Extract and print level 1 and 2 titles from workshop slides. 7 | """ 8 | os.chdir("../slides") 9 | 10 | with open("showoff.json", "r") as f: 11 | data = f.read() 12 | 13 | data = data.replace('\n', '') 14 | while ' ' in data: 15 | data = data.replace(' ', ' ') 16 | data = data.replace('//', '') 17 | data = json.loads(data) 18 | 19 | sections = data["sections"] 20 | page = 0 21 | for section in sections: 22 | #page += 1 23 | directory, filename = section.split('/') 24 | print("{}: {}".format( 25 | click.style(directory, fg='red'), 26 | click.style(filename, fg='yellow') 27 | )) 28 | with open(section, "r") as f: 29 | slides = f.read() 30 | slides = slides.split("