19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/doc/00-docker-basics/readme.md:
--------------------------------------------------------------------------------
1 | # [](http://harbur.io) Docker Workshop - Docker Basics
2 |
3 | This section is separated in:
4 |
5 | * [CLI Basics](#cli-basics)
6 | * [Dockerfile basics](#dockerfile-basics)
7 |
8 | # CLI Basics
9 |
10 | ### Version
11 |
12 | Check you have latest version of docker installed:
13 |
14 | ```
15 | docker version
16 | ```
17 |
18 | * If you don't have docker installed, check [here](https://docs.docker.com/installation/#installation)
19 | * If you're not on the latest version, it will prompt you to update
20 | * If you're not on docker group you might need to prefix commands with `sudo`. See [here](http://docs.docker.com/installation/ubuntulinux/#giving-non-root-access) for details about it.
21 |
22 | ### Commands
23 |
24 | Check the available docker commands
25 |
26 | ```
27 | docker
28 | ```
29 |
30 | * Whenever you don't remember a command, just type docker
31 | * For more info, type `docker help COMMAND` (e.g. `docker help run`)
32 |
33 | ### RUN a "Hello World" container
34 |
35 | ```
36 | docker run alpine echo "Hello World"
37 | ```
38 |
39 | * If the Image is not cached, it pulls it automatically
40 | * It prints `Hello World` and exits
41 |
42 | ### RUN an interactive Container
43 |
44 | ```
45 | docker run -it alpine sh
46 | cat /etc/os-release
47 | ```
48 |
49 | * **-i**: Keep stdin open even if not attached
50 | * **-t**: Allocate a pseudo-tty
51 |
52 | ### RUN a Container with pipeline
53 |
54 | ```
55 | cat /etc/resolv.conf | docker run -i alpine wc -l
56 | ```
57 |
58 | ### SEARCH a Container
59 |
60 | ```
61 | docker search -s 10 nginx
62 | ```
63 |
64 | * **-s**: Only displays with at least x stars
65 |
66 | ### RUN a Container and expose a Port
67 |
68 | On Linux:
69 | ```
70 | docker run -d -p 4000:80 nginx
71 | google-chrome localhost:4000
72 | ```
73 |
74 | On Mac:
75 | ```
76 | docker run -d -p 4000:80 nginx
77 | open "http://$(docker-machine ip default):4000"
78 | ```
79 |
80 | * **-d**: Detached mode: Run container in the background, print new container id
81 | * **-p**: Publish a container's port to the host (format: *hostPort:containerPort*)
82 | * For more info about the container, see [nginx](https://registry.hub.docker.com/_/nginx/)
83 |
84 | ### RUN a Container with a Volume
85 |
86 | NOTE: Make sure to be on `Docker Workshop` directory since we'll use volume mounts in the containers of directories of the repository.
87 |
88 | On Linux:
89 | ```
90 | docker run -d -p 4001:80 -v $(pwd)/code/hello-world/site/:/usr/share/nginx/html:ro nginx
91 | google-chrome localhost:4001
92 | ```
93 |
94 | On Mac:
95 | ```
96 | docker run -d -p 4001:80 -v $(pwd)/code/hello-world/site/:/usr/share/nginx/html:ro nginx
97 | open "http://$(docker-machine ip default):4001"
98 | ```
99 |
100 | * **-v**: Bind mount a volume (e.g., from the host: -v /host:/container, from docker: -v /container)
101 | * The volume is **linked** inside the container. Any external changes are visible directly inside the container.
102 | * This example breaks the immutability of the container, good for debuging, not recommended for production (Volumes should be used for data, not code)
103 |
104 | ## Exercise 1 (10 mins)
105 |
106 | * Build a static website
107 | * Run it on your machine
108 | * Share your (non-localhost) url on [Slack](https://dockerbcn.herokuapp.com)
109 |
110 | # Dockerfile Basics
111 |
112 | ### BUILD a Git Client Container
113 |
114 | Create a Git Container manually:
115 |
116 | ```
117 | docker run -it --name git alpine sh
118 | apk --update add git
119 | git version
120 | exit
121 | docker commit git docker-git
122 | docker rm git
123 | docker run --rm -it docker-git git version
124 | docker rmi docker-git
125 | ```
126 |
127 | * **--name**: Assign a name to the container
128 | * **commit**: Create a new image from a container's changes
129 | * **rm**: Remove one or more containers
130 | * **rmi**: Remove one or more images
131 | * **--rm**: Automatically remove the container when it exits
132 |
133 | Create a Git Container with Dockerfile:
134 |
135 | ```
136 | cd code/docker-git
137 | docker build -t docker-git .
138 | docker run -it docker-git git version
139 | ```
140 |
141 | * **build**: Build an image from a Dockerfile
142 |
143 | [code/docker-git/Dockerfile](../../code/docker-git/Dockerfile)
144 | ```
145 | FROM alpine:3.3
146 | RUN apk update
147 | RUN apk add git
148 | ```
149 |
150 | * The **FROM** instruction sets the Base Image for subsequent instructions
151 | * The **RUN** instruction will execute any commands in a new layer on top of the current image and commit the results
152 |
153 | ### BUILD an Apache Server Container
154 |
155 | Create an Apache Server Container with Dockerfile:
156 |
157 | ```
158 | cd code/docker-apache2
159 | docker build -t docker-apache2 .
160 | docker run -d -p 4003:80 docker-apache2
161 | ```
162 |
163 | On Linux:
164 | ```
165 | google-chrome localhost:4003
166 | ```
167 |
168 | On Mac:
169 | ```
170 | open "http://$(docker-machine ip default):4003"
171 | ```
172 |
173 | [code/docker-apache2/Dockerfile](../../code/docker-apache2/Dockerfile)
174 | ```
175 | FROM alpine:3.3
176 | RUN apk --update add apache2 && rm -rf /var/cache/apk/*
177 | RUN mkdir -p /run/apache2
178 | EXPOSE 80
179 | CMD httpd -D FOREGROUND
180 | ```
181 |
182 | * The **EXPOSE** instructions informs Docker that the container will listen on the specified network ports at runtime
183 | * The **CMD** instruction sets the command to be executed when running the image
184 |
185 | ### BUILD a Static website Image
186 |
187 | ```
188 | cd code/hello-world
189 | docker build -t hello-world .
190 | docker run -d --name hello -P hello-world
191 | ```
192 |
193 | On Linux:
194 | ```
195 | google-chrome $(docker port hello 80)
196 | ```
197 |
198 | On Mac:
199 | ```
200 | open "http://$(docker-machine ip default):${$(docker port hello 80)##*:}"
201 | ```
202 |
203 | * **-P**: Publish all exposed ports to the host interfaces
204 | * **port**: Lookup the public-facing port that is NAT-ed to PRIVATE_PORT
205 |
206 | [code/hello-world/Dockerfile](../../code/hello-world/Dockerfile)
207 | ```
208 | FROM nginx:1.8-alpine
209 | ADD site /usr/share/nginx/html
210 | ```
211 |
212 | * The **ADD** instruction will copy new files from and add them to the container's filesystem at path
213 |
214 | ## Exercise 2 (10 mins)
215 |
216 | * Build your website with Dockerfile
217 | * Run an instance
218 | * Share your (non-localhost) url on [Slack](https://dockerbcn.herokuapp.com)
219 |
220 | ### PUSH Image to a Registry
221 |
222 | For this step, we'll need to launch a registry:
223 |
224 | ```
225 | docker run -d -p 5000:5000 --name registry registry:2
226 | ```
227 |
228 | Then tag your image under the registry namespace and push it there:
229 |
230 | ```
231 | REGISTRY=localhost:5000
232 | docker tag hello-world $REGISTRY/$(whoami)/hello-world
233 | docker push $REGISTRY/$(whoami)/hello-world
234 | ```
235 |
236 | * **tag**: Tag an image into a repository
237 | * **push**: Push an image or a repository to a Docker registry server
238 |
239 | ## Exercise 3 (10 mins)
240 |
241 | * Push your website to the local Registry (use your github username)
242 | * Push your website image
243 | * Share your image name on [Slack](https://dockerbcn.herokuapp.com)
244 |
245 | ### PULL Image from a Repository
246 |
247 | ```
248 | docker pull $REGISTRY/$(whoami)/hello-world
249 | docker run -d -P --name=registry-hello $REGISTRY/$(whoami)/hello-world
250 | ```
251 |
252 | On Linux:
253 | ```
254 | google-chrome $(docker port registry-hello 80)
255 | ```
256 |
257 | On Mac:
258 | ```
259 | open "http://$(docker-machine ip default):${$(docker port registry-hello 80)##*:}"
260 | ```
261 |
262 | * **pull**: Pull an image or a repository from a Docker registry server
263 |
264 |
265 | # Navigation
266 |
267 | Previous | Next
268 | :------- | ---:
269 | ← [Docker Workshop - Home](https://github.com/harbur/docker-workshop) | [Docker Workshop - Docker machine](../01-docker-machine) →
270 |
271 | # Credits
272 |
273 | This workshop was prepared by [harbur.io](http://harbur.io), under MIT License. Feel free to fork and improve.
274 |
--------------------------------------------------------------------------------
/doc/01-docker-machine/readme.md:
--------------------------------------------------------------------------------
1 | # [](http://harbur.io) Docker Workshop - Docker machine
2 |
3 | In this section we'll introduce `docker-machine`.
4 |
5 | ## Install Docker Toolbox
6 |
7 | Download and install [Docker Toolbox](https://www.docker.com/docker-toolbox).
8 |
9 | The toolbox installs a handful of tools on your local Windows or Mac OS X computer. In this exercise, you use two of those tools:
10 |
11 | * Docker Machine: To deploy virtual machines that run Docker Engine
12 | * VirtualBox: To host the virtual machines deployed from Docker Machine
13 |
14 |
15 | ## Create a VM running Docker
16 |
17 | Open a terminal on your computer.
18 |
19 | Create and run a VM named `default` using the following command:
20 |
21 | ```
22 | docker-machine create -d virtualbox default
23 | ```
24 |
25 | You can list the existing docker-machines:
26 |
27 | ```
28 | docker-machine ls
29 | ```
30 |
31 | In case you already had the machine created, you can simply start the VM:
32 |
33 | ```
34 | docker-machine start default
35 | ```
36 |
37 | ## Run a docker container in a docker-machine
38 |
39 | Now, let's use the docker-machine we've just created. We want to run the `hello-world`.
40 |
41 | If you use Mac, you need to run:
42 | ```
43 | eval $(docker-machine env default)
44 | ```
45 |
46 | This command set the `DOCKER_HOST` variable to the IP of your `default` `docker-machine`.
47 |
48 | Then we can run the `hello-world` container:
49 | ```
50 | docker run hello-world
51 | ```
52 |
53 | ## Clean up
54 |
55 | After we tested our `default` `docker-machine` we want to remove it from our computer.
56 |
57 | Stop the VM named `default`:
58 |
59 | ```
60 | docker-machine stop default
61 | ```
62 |
63 | You can destroy the VM named `default`:
64 |
65 | ```
66 | docker-machine rm default
67 | ```
68 |
69 | ## Create two machines
70 |
71 | To create two machines do:
72 |
73 | ```
74 | docker-machine create -d virtualbox client1
75 | docker-machine create -d virtualbox client2
76 | ```
77 |
78 | Now you can see the machines with:
79 |
80 | ```
81 | docker-machine ls
82 | ```
83 |
84 | ## Run Nginx on client1
85 |
86 | ```
87 | eval $(docker-machine env client1)
88 | docker run -d -p 80:80 nginx:1.8-alpine
89 | docker-machine ip client1
90 | open "http://$(docker-machine ip client1)"
91 | ```
92 |
93 | ## Run Nginx on client2
94 |
95 | ```
96 | eval $(docker-machine env client2)
97 | docker run -d -p 80:80 nginx:1.8-alpine
98 | docker-machine ip client2
99 | open "http://$(docker-machine ip client2)"
100 | ```
101 |
102 | ## SSH to machine
103 |
104 | To SSH inside a machine:
105 |
106 | ```
107 | docker-machine ssh client1
108 | ```
109 |
110 | ## Environment variables
111 |
112 | Docker client is configured by environment variables to connect with remote daemons. The following command outputs the variables for connecting to previously created `default` VM.
113 |
114 | ```
115 | docker-machine env default
116 | ```
117 |
118 | ## Active Machine
119 |
120 | To get the active machine's name do:
121 |
122 | ```
123 | docker-machine active
124 | ```
125 |
126 | ## Cleanup
127 |
128 |
129 | ```
130 | docker-machine stop client1 client2
131 | docker-machine rm client1 client2
132 | ```
133 |
134 |
135 | # Navigation
136 |
137 | Previous | Next
138 | :------- | ---:
139 | ← [Docker Workshop - Docker Basics](../00-docker-basics) | [Docker Workshop - Docker Compose](../02-docker-compose) →
140 |
141 | # Credits
142 |
143 | This workshop was prepared by [harbur.io](http://harbur.io), under MIT License. Feel free to fork and improve.
--------------------------------------------------------------------------------
/doc/02-docker-compose/readme.md:
--------------------------------------------------------------------------------
1 | # [](http://harbur.io) Docker Workshop - Docker Compose
2 |
3 |
4 | This section will show how to use Docker Compose with some small exercises and with a simple Node/Redis app. Before starting, you'll need to have [Docker Compose installed](https://docs.docker.com/compose/install/).
5 |
6 | # Docker-compose
7 |
8 | Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a Compose file to configure your application’s services. Then, using a single command, you create and start all the services from your configuration. To learn more about all the features of Compose see [the list of features](https://docs.docker.com/compose/overview/#features).
9 |
10 | Using Compose is basically a three-step process:
11 |
12 | 1. Define your app’s environment with a `Dockerfile` so it can be reproduced anywhere.
13 | 1. Define the services that make up your app in `docker-compose.yml` so they can be run together in an isolated environment.
14 | 1. Lastly, run `docker-compose up` and Compose will start and run your entire app.
15 |
16 |
17 | ## Commands
18 |
19 | Check the available commands of Docker Compose. Type in your terminal:
20 |
21 | ```
22 | docker-compose
23 | ```
24 |
25 | * Whenever you don't remember a command, just type docker-compose
26 | * For more info, type `docker-compose help COMMAND` (e.g. `docker-compose help build`)
27 |
28 | ## docker-compose.yml
29 |
30 | The `docker-compose.yml` file is a [YAML](http://yaml.org/) file defining [services](https://docs.docker.com/compose/compose-file/#service-configuration-reference), [networks](https://docs.docker.com/compose/compose-file/#network-configuration-reference) and [volumes](https://docs.docker.com/compose/compose-file/#volume-configuration-reference). The default path for a Compose file is `./docker-compose.yml`.
31 |
32 | A service definition contains configuration which will be applied to each container started for that service, much like passing command-line parameters to `docker run`. Likewise, network and volume definitions are analogous to `docker network create` and `docker volume create`.
33 |
34 | Options specified in the `Dockerfile` (e.g., `CMD`, `EXPOSE`, `VOLUME`, `ENV`) are respected by default - you don’t need to specify them again in `docker-compose.yml`.
35 |
36 |
37 | ## Project's components
38 |
39 | We've already created a simple app in `code/guestbook-node` that uses node.js with express and redis.
40 |
41 | 1. Go to `code/guestbook-node` folder
42 |
43 | 2. Review `Dockerfile`:
44 |
45 | ```
46 | FROM node:7.7.0-alpine
47 | RUN mkdir /code
48 | WORKDIR /code
49 | ADD package.json /code/
50 | RUN npm install
51 | ADD . /code/
52 | CMD ["node", "main.js"]
53 | ```
54 |
55 | We use the base image of `node:7.7.0-alpine`. It is the official image in Alpine, a minimal OS.
56 |
57 | The `Dockerfile` then creates the directory where our code will be stored, `/code`, and it copies the `package.json` so it can install the node dependencies.
58 |
59 | Afterwards it copies all the code we have in the host machine and runs the command that will keep the container running.
60 |
61 | 3. Review `docker-compose.yml`:
62 |
63 | ```
64 | version: '2'
65 | services:
66 | redis:
67 | image: redis:alpine
68 | web:
69 | build: .
70 | ports:
71 | - "80:3000"
72 | depends_on:
73 | - redis
74 | ```
75 |
76 | The `docker-compose.yml` file describes the services that make your app. In this example those services are a web server and database. The compose file also describes which Docker images these services use, how they link together, any volumes they might need mounted inside the containers. Finally, the `docker-compose.yml` file describes which ports these services expose. See the docker-compose.yml [reference](https://docs.docker.com/compose/compose-file/) for more information on how this file works.
77 |
78 | In this case, we defined two services, `redis` that uses `redis:alpine` and `web`, our nodejs app. We linked the two of them, and `web` depends on `redis` as you can see in `depends_on`. Also, our nodejs app listens the port `3000` so we linked host's port 80 to the docker container 3000 port.
79 |
80 |
81 | ## Run the app
82 |
83 | ### Build the images
84 |
85 | With docker-compose we can build all the images at once running:
86 | ```
87 | docker-compose build
88 | ```
89 |
90 | The `docker-compose build` reads `docker-compose.yml` and build all the services defined in there.
91 |
92 | ### Run a command against a service
93 | We can run a one-time command against a service. For example, the following command starts the `web` service and runs `sh` as its command.
94 | ```
95 | docker-compose run web sh
96 | ```
97 |
98 | Commands you use with `run` start in new containers with the same configuration as defined by the service's configuration. This means the container has the same volumes, links, as defined in the configuration file. There two differences though.
99 |
100 | First, the command passed by `run` overrides the command defined in the service configuration. For example, if the `web` service configuration is started with `node`, then `docker-compose run web sh` overrides it with `sh`.
101 |
102 | The second difference is the `docker-compose run` command does not create any of the ports specified in the service configuration. This prevents the port collisions with already open ports.
103 |
104 | ### Start services
105 |
106 | We can run `docker-compose up` that builds, (re)creates, starts, and attaches to containers for a service. Unless they are already running, this command also starts any linked services.
107 |
108 | Type in your terminal:
109 |
110 | ```
111 | docker-compose up
112 | ```
113 |
114 | This instructs Compose to run the services defined in the `docker-compose.yml` in containers, using the `redis` image and the `web` service's image and configuration.
115 |
116 | The docker-compose up command aggregates the output of each container. When the command exits, all containers are stopped.
117 |
118 | If we want, we can run the containers in background with `-d` flag:
119 | ```
120 | docker-compose up -d
121 | ```
122 |
123 | At this point, your Node app should be running at port `8088` on your Docker host. If you are using a Docker Machine VM, you can use the `docker-machine ip MACHINE_NAME` to get the IP address.
124 |
125 | ### Logs
126 |
127 | We can see the log output from services running:
128 | ```
129 | docker-compose logs
130 | ```
131 |
132 | If we want to review the logs of a specific service, e.g. `web`:
133 | ```
134 | docker-compose logs web
135 | ```
136 |
137 | ### List containers
138 |
139 | We can run `ps` like in `docker ps` to list containers and their status:
140 | ```
141 | docker-compose ps
142 | ```
143 |
144 | ### Stop containers
145 |
146 | ```
147 | docker-compose stop
148 | ```
149 |
150 | Stops running containers without removing them. They can be started again with `docker-compose start`.
151 |
152 | If we want we can stop only one container:
153 | ```
154 | docker-compose stop web
155 | ```
156 |
157 | ### Start container
158 |
159 | Starts existing containers for a service, e.g. `web`:
160 | ```
161 | docker-compose start web
162 | ```
163 |
164 | ### Remove containers
165 | ```
166 | docker-compose rm
167 | ```
168 |
169 | The previous command removes __stopped__ service containers.
170 |
171 | If we want to stop and remove them:
172 |
173 | ```
174 | docker-compose down
175 | ```
176 |
177 | ## Exercise 1 (10 min)
178 |
179 | Update the title of `guestbook` app adding your name.
180 |
181 | The goal of this exercise is:
182 | - Understand the development process
183 | - Understand how to update the code and deploy it
184 |
185 |
186 | ## Exercise 2 (15 min)
187 |
188 | Add a new service like `web` in the `docker-compose.yml` to have another application that connects to the existing `redis` and expose a different port.
189 |
190 | The goal of this exercise is:
191 |
192 | - Understand how `docker-compose.yml` works
193 | - Understand how to add a new service
194 | - Understand how to expose ports
195 | - Be able to run at the same time the two `web` containers
196 |
197 | # Navigation
198 |
199 | Previous | Next
200 | :------- | ---:
201 | ← [Docker Workshop - Docker machine](../01-docker-machine) | [Docker Workshop - Home](https://github.com/harbur/docker-workshop) →
202 |
203 | # Credits
204 |
205 | This workshop was prepared by [harbur.io](http://harbur.io), under MIT License. Feel free to fork and improve.
206 |
--------------------------------------------------------------------------------