diff --git a/slides/intro-container-security.yml.html b/slides/intro-container-security.yml.html
index 3a9b0c7..759351a 100644
--- a/slides/intro-container-security.yml.html
+++ b/slides/intro-container-security.yml.html
@@ -31,13 +31,11 @@ i share: Introduction Container Security and Hardening
```
M slides/airgapped/Importing_Images.md
M slides/intro-container-security.yml.html
- M slides/swarm-halfday.yml.html
- M slides/swarm-selfpaced.yml.html
- M slides/swarm-video.yml.html
+ M slides/intro-fd-docker.yml
```
-These slides have been built from commit: 65fec64
+These slides have been built from commit: 1e1b023
[shared/title.md](""/tree/main/slides/shared/title.md)]
diff --git a/slides/intro-fd-docker.yml.html b/slides/intro-fd-docker.yml.html
index 3c602c8..71fcf26 100644
--- a/slides/intro-fd-docker.yml.html
+++ b/slides/intro-fd-docker.yml.html
@@ -31,14 +31,12 @@ Introduction to Containers in an Airgapped Environment
```
M slides/airgapped/Importing_Images.md
M slides/intro-container-security.yml.html
+ M slides/intro-fd-docker.yml
M slides/intro-fd-docker.yml.html
- M slides/swarm-halfday.yml.html
- M slides/swarm-selfpaced.yml.html
- M slides/swarm-video.yml.html
```
-These slides have been built from commit: 65fec64
+These slides have been built from commit: 1e1b023
[shared/title.md](""/tree/main/slides/shared/title.md)]
@@ -554,8 +552,6 @@ name: toc-part-4
- [Local development workflow with Docker](#toc-local-development-workflow-with-docker)
-- [Compose for development stacks](#toc-compose-for-development-stacks)
-
.debug[(auto-generated TOC)]
---
@@ -563,7 +559,7 @@ name: toc-part-5
## Part 5
-- [Our sample application](#toc-our-sample-application)
+- [Logging](#toc-logging)
- [Links and resources](#toc-links-and-resources)
@@ -4395,7 +4391,7 @@ class: title
|
[Back to table of contents](#toc-part-4)
|
-[Next part](#toc-compose-for-development-stacks)
+[Next part](#toc-logging)
]
.debug[(automatically generated title slide)]
@@ -4885,551 +4881,14 @@ class: pic
---
-name: toc-compose-for-development-stacks
+name: toc-logging
class: title
- Compose for development stacks
+ Logging
.nav[
[Previous part](#toc-local-development-workflow-with-docker)
|
-[Back to table of contents](#toc-part-4)
-|
-[Next part](#toc-our-sample-application)
-]
-
-.debug[(automatically generated title slide)]
-
----
-# Compose for development stacks
-
-Dockerfile = great to build *one* container image.
-
-What if we have multiple containers?
-
-What if some of them require particular `docker run` parameters?
-
-How do we connect them all together?
-
-... Compose solves these use-cases (and a few more).
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Life before Compose
-
-Before we had Compose, we would typically write custom scripts to:
-
-- build container images,
-
-- run containers using these images,
-
-- connect the containers together,
-
-- rebuild, restart, update these images and containers.
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Life with Compose
-
-Compose enables a simple, powerful onboarding workflow:
-
-1. Checkout our code.
-
-2. Run `docker-compose up`.
-
-3. Our app is up and running!
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-class: pic
-
-
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Life after Compose
-
-(Or: when do we need something else?)
-
-- Compose is *not* an orchestrator
-
-- It isn't designed to need to run containers on multiple nodes
-
- (it can, however, work with Docker Swarm Mode)
-
-- Compose isn't ideal if we want to run containers on Kubernetes
-
- - it uses different concepts (Compose services ≠ Kubernetes services)
-
- - it needs a Docker Engine (although containerd support might be coming)
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## First rodeo with Compose
-
-1. Write Dockerfiles
-
-2. Describe our stack of containers in a YAML file called `docker-compose.yml`
-
-3. `docker-compose up` (or `docker-compose up -d` to run in the background)
-
-4. Compose pulls and builds the required images, and starts the containers
-
-5. Compose shows the combined logs of all the containers
-
- (if running in the background, use `docker-compose logs`)
-
-6. Hit Ctrl-C to stop the whole stack
-
- (if running in the background, use `docker-compose stop`)
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Iterating
-
-After making changes to our source code, we can:
-
-1. `docker-compose build` to rebuild container images
-
-2. `docker-compose up` to restart the stack with the new images
-
-We can also combine both with `docker-compose up --build`
-
-Compose will be smart, and only recreate the containers that have changed.
-
-When working with interpreted languages:
-
-- don't rebuild each time
-
-- leverage a `volumes` section instead
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Launching Our First Stack with Compose
-
-First step: clone the source code for the app we will be working on.
-
-```bash
-git clone https://github.com/jpetazzo/trainingwheels
-cd trainingwheels
-```
-
-Second step: start the app.
-
-```bash
-docker-compose up
-```
-
-Watch Compose build and run the app.
-
-That Compose stack exposes a web server on port 8000; try connecting to it.
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Launching Our First Stack with Compose
-
-We should see a web page like this:
-
-
-
-Each time we reload, the counter should increase.
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Stopping the app
-
-When we hit Ctrl-C, Compose tries to gracefully terminate all of the containers.
-
-After ten seconds (or if we press `^C` again) it will forcibly kill them.
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## The `docker-compose.yml` file
-
-Here is the file used in the demo:
-
-.small[
-```yaml
-version: "3"
-
-services:
- www:
- build: www
- ports:
- - ${PORT-8000}:5000
- user: nobody
- environment:
- DEBUG: 1
- command: python counter.py
- volumes:
- - ./www:/src
-
- redis:
- image: redis
-```
-]
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Compose file structure
-
-A Compose file has multiple sections:
-
-* `version` is mandatory. (Typically use "3".)
-
-* `services` is mandatory. Each service corresponds to a container.
-
-* `networks` is optional and indicates to which networks containers should be connected.
- (By default, containers will be connected on a private, per-compose-file network.)
-
-* `volumes` is optional and can define volumes to be used and/or shared by the containers.
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Compose file versions
-
-* Version 1 is legacy and shouldn't be used.
-
- (If you see a Compose file without `version` and `services`, it's a legacy v1 file.)
-
-* Version 2 added support for networks and volumes.
-
-* Version 3 added support for deployment options (scaling, rolling updates, etc).
-
-* Typically use `version: "3"`.
-
-The [Docker documentation](https://docs.docker.com/compose/compose-file/)
-has excellent information about the Compose file format if you need to know more about versions.
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Containers in `docker-compose.yml`
-
-Each service in the YAML file must contain either `build`, or `image`.
-
-* `build` indicates a path containing a Dockerfile.
-
-* `image` indicates an image name (local, or on a registry).
-
-* If both are specified, an image will be built from the `build` directory and named `image`.
-
-The other parameters are optional.
-
-They encode the parameters that you would typically add to `docker run`.
-
-Sometimes they have several minor improvements.
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Container parameters
-
-* `command` indicates what to run (like `CMD` in a Dockerfile).
-
-* `ports` translates to one (or multiple) `-p` options to map ports.
- You can specify local ports (i.e. `x:y` to expose public port `x`).
-
-* `volumes` translates to one (or multiple) `-v` options.
- You can use relative paths here.
-
-For the full list, check: https://docs.docker.com/compose/compose-file/
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Environment variables
-
-- We can use environment variables in Compose files
-
- (like `$THIS` or `${THAT}`)
-
-- We can provide default values, e.g. `${PORT-8000}`
-
-- Compose will also automatically load the environment file `.env`
-
- (it should contain `VAR=value`, one per line)
-
-- This is a great way to customize build and run parameters
-
- (base image versions to use, build and run secrets, port numbers...)
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Configuring a Compose stack
-
-- Follow [12-factor app configuration principles][12factorconfig]
-
- (configure the app through environment variables)
-
-- Provide (in the repo) a default environment file suitable for development
-
- (no secret or sensitive value)
-
-- Copy the default environment file to `.env` and tweak it
-
- (or: provide a script to generate `.env` from a template)
-
-[12factorconfig]: https://12factor.net/config
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Running multiple copies of a stack
-
-- Copy the stack in two different directories, e.g. `front` and `frontcopy`
-
-- Compose prefixes images and containers with the directory name:
-
- `front_www`, `front_www_1`, `front_db_1`
-
- `frontcopy_www`, `frontcopy_www_1`, `frontcopy_db_1`
-
-- Alternatively, use `docker-compose -p frontcopy`
-
- (to set the `--project-name` of a stack, which default to the dir name)
-
-- Each copy is isolated from the others (runs on a different network)
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Checking stack status
-
-We have `ps`, `docker ps`, and similarly, `docker-compose ps`:
-
-```bash
-$ docker-compose ps
-Name Command State Ports
-----------------------------------------------------------------------------
-trainingwheels_redis_1 /entrypoint.sh red Up 6379/tcp
-trainingwheels_www_1 python counter.py Up 0.0.0.0:8000->5000/tcp
-```
-
-Shows the status of all the containers of our stack.
-
-Doesn't show the other containers.
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Cleaning up (1)
-
-If you have started your application in the background with Compose and
-want to stop it easily, you can use the `kill` command:
-
-```bash
-$ docker-compose kill
-```
-
-Likewise, `docker-compose rm` will let you remove containers (after confirmation):
-
-```bash
-$ docker-compose rm
-Going to remove trainingwheels_redis_1, trainingwheels_www_1
-Are you sure? [yN] y
-Removing trainingwheels_redis_1...
-Removing trainingwheels_www_1...
-```
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Cleaning up (2)
-
-Alternatively, `docker-compose down` will stop and remove containers.
-
-It will also remove other resources, like networks that were created for the application.
-
-```bash
-$ docker-compose down
-Stopping trainingwheels_www_1 ... done
-Stopping trainingwheels_redis_1 ... done
-Removing trainingwheels_www_1 ... done
-Removing trainingwheels_redis_1 ... done
-```
-
-Use `docker-compose down -v` to remove everything including volumes.
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Special handling of volumes
-
-- When an image gets updated, Compose automatically creates a new container
-
-- The data in the old container is lost...
-
-- ...Except if the container is using a *volume*
-
-- Compose will then re-attach that volume to the new container
-
- (and data is then retained across database upgrades)
-
-- All good database images use volumes
-
- (e.g. all official images)
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Gotchas with volumes
-
-- Unfortunately, Docker volumes don't have labels or metadata
-
-- Compose tracks volumes thanks to their associated container
-
-- If the container is deleted, the volume gets orphaned
-
-- Example: `docker-compose down && docker-compose up`
-
- - the old volume still exists, detached from its container
-
- - a new volume gets created
-
-- `docker-compose down -v`/`--volumes` deletes volumes
-
- (but **not** `docker-compose down && docker-compose down -v`!)
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Managing volumes explicitly
-
-Option 1: *named volumes*
-
-```yaml
-services:
- app:
- volumes:
- - data:/some/path
-volumes:
- data:
-```
-
-- Volume will be named `_data`
-
-- It won't be orphaned with `docker-compose down`
-
-- It will correctly be removed with `docker-compose down -v`
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Managing volumes explicitly
-
-Option 2: *relative paths*
-
-```yaml
-services:
- app:
- volumes:
- - ./data:/some/path
-```
-
-- Makes it easy to colocate the app and its data
-
- (for migration, backups, disk usage accounting...)
-
-- Won't be removed by `docker-compose down -v`
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Managing complex stacks
-
-- Compose provides multiple features to manage complex stacks
-
- (with many containers)
-
-- `-f`/`--file`/`$COMPOSE_FILE` can be a list of Compose files
-
- (separated by `:` and merged together)
-
-- Services can be assigned to one or more *profiles*
-
-- `--profile`/`$COMPOSE_PROFILE` can be a list of comma-separated profiles
-
- (see [Using service profiles][profiles] in the Compose documentation)
-
-- These variables can be set in `.env`
-
-[profiles]: https://docs.docker.com/compose/profiles/
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-## Dependencies
-
-- A service can have a `depends_on` section
-
- (listing one or more other services)
-
-- This is used when bringing up individual services
-
- (e.g. `docker-compose up blah` or `docker-compose run foo`)
-
-⚠️ It doesn't make a service "wait" for another one to be up!
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-class: extra-details
-
-## A bit of history and trivia
-
-- Compose was initially named "Fig"
-
-- Compose is one of the only components of Docker written in Python
-
- (almost everything else is in Go)
-
-- In 2020, Docker introduced "Compose CLI":
-
- - `docker compose` command to deploy Compose stacks to some clouds
-
- - progressively getting feature parity with `docker-compose`
-
- - also provides numerous improvements (e.g. leverages BuildKit by default)
-
-???
-
-:EN:- Using compose to describe an environment
-:EN:- Connecting services together with a *Compose file*
-
-:FR:- Utiliser Compose pour décrire son environnement
-:FR:- Écrire un *Compose file* pour connecter les services entre eux
-
-.debug[[containers/Compose_For_Dev_Stacks.md](""/tree/main/slides/containers/Compose_For_Dev_Stacks.md)]
----
-
-class: pic
-
-.interstitial[]
-
----
-
-name: toc-our-sample-application
-class: title
-
- Our sample application
-
-.nav[
-[Previous part](#toc-compose-for-development-stacks)
-|
[Back to table of contents](#toc-part-5)
|
[Next part](#toc-links-and-resources)
@@ -5438,385 +4897,327 @@ class: title
.debug[(automatically generated title slide)]
---
-# Our sample application
+# Logging
-- We will clone the GitHub repository onto our `node1`
+In this chapter, we will explain the different ways to send logs from containers.
-- The repository also contains scripts and tools that we will use through the workshop
+We will then show one particular method in action, using ELK and Docker's logging drivers.
-.lab[
+.debug[[containers/Logging.md](""/tree/main/slides/containers/Logging.md)]
+---
-
-- Clone the repository on `node1`:
- ```bash
- git clone https://github.com/jpetazzo/container.training
- ```
-
-]
-
-(You can also fork the repository on GitHub and clone your fork if you prefer that.)
-
-.debug[[shared/sampleapp.md](""/tree/main/slides/shared/sampleapp.md)]
+.debug[[containers/Logging.md](""/tree/main/slides/containers/Logging.md)]
---
-## Downloading and running the application
+## Demo: sending logs to ELK
-Let's start this before we look around, as downloading will take a little time...
+- We are going to deploy an ELK stack.
-.lab[
+- It will accept logs over a GELF socket.
-- Go to the `dockercoins` directory, in the cloned repository:
- ```bash
- cd ~/container.training/dockercoins
- ```
+- We will run a few containers with the `gelf` logging driver.
-- Use Compose to build and run all containers:
- ```bash
- docker-compose up
- ```
+- We will then see our logs in Kibana, the web interface provided by ELK.
-
+*Important foreword: this is not an "official" or "recommended"
+setup; it is just an example. We used ELK in this demo because
+it's a popular setup and we keep being asked about it; but you
+will have equal success with Fluent or other logging stacks!*
-]
-
-Compose tells Docker to build all container images (pulling
-the corresponding base images), then starts all containers,
-and displays aggregated logs.
-
-.debug[[shared/sampleapp.md](""/tree/main/slides/shared/sampleapp.md)]
+.debug[[containers/Logging.md](""/tree/main/slides/containers/Logging.md)]
---
-## What's this application?
+## What's in an ELK stack?
---
+- ELK is three components:
-- It is a DockerCoin miner! 💰🐳📦🚢
+ - ElasticSearch (to store and index log entries)
---
+ - Logstash (to receive log entries from various
+ sources, process them, and forward them to various
+ destinations)
-- No, you can't buy coffee with DockerCoin
+ - Kibana (to view/search log entries with a nice UI)
---
+- The only component that we will configure is Logstash
-- How dockercoins works:
+- We will accept log entries using the GELF protocol
- - generate a few random bytes
+- Log entries will be stored in ElasticSearch,
+ and displayed on Logstash's stdout for debugging
- - hash these bytes
-
- - increment a counter (to keep track of speed)
-
- - repeat forever!
-
---
-
-- DockerCoin is *not* a cryptocurrency
-
- (the only common points are "randomness," "hashing," and "coins" in the name)
-
-.debug[[shared/sampleapp.md](""/tree/main/slides/shared/sampleapp.md)]
+.debug[[containers/Logging.md](""/tree/main/slides/containers/Logging.md)]
---
-## DockerCoin in the microservices era
+## Running ELK
-- The dockercoins app is made of 5 services:
+- We are going to use a Compose file describing the ELK stack.
- - `rng` = web service generating random bytes
+- The Compose file is in the container.training repository on GitHub.
- - `hasher` = web service computing hash of POSTed data
+```bash
+$ git clone https://github.com/jpetazzo/container.training
+$ cd container.training
+$ cd elk
+$ docker-compose up
+```
- - `worker` = background process calling `rng` and `hasher`
+- Let's have a look at the Compose file while it's deploying.
- - `webui` = web interface to watch progress
-
- - `redis` = data store (holds a counter updated by `worker`)
-
-- These 5 services are visible in the application's Compose file,
- [docker-compose.yml](
- https://github.com/jpetazzo/container.training/blob/master/dockercoins/docker-compose.yml)
-
-.debug[[shared/sampleapp.md](""/tree/main/slides/shared/sampleapp.md)]
+.debug[[containers/Logging.md](""/tree/main/slides/containers/Logging.md)]
---
-## How dockercoins works
+## Our basic ELK deployment
-- `worker` invokes web service `rng` to generate random bytes
+- We are using images from the Docker Hub: `elasticsearch`, `logstash`, `kibana`.
-- `worker` invokes web service `hasher` to hash these bytes
+- We don't need to change the configuration of ElasticSearch.
-- `worker` does this in an infinite loop
+- We need to tell Kibana the address of ElasticSearch:
-- every second, `worker` updates `redis` to indicate how many loops were done
+ - it is set with the `ELASTICSEARCH_URL` environment variable,
-- `webui` queries `redis`, and computes and exposes "hashing speed" in our browser
+ - by default it is `localhost:9200`, we change it to `elasticsearch:9200`.
-*(See diagram on next slide!)*
+- We need to configure Logstash:
-.debug[[shared/sampleapp.md](""/tree/main/slides/shared/sampleapp.md)]
+ - we pass the entire configuration file through command-line arguments,
+
+ - this is a hack so that we don't have to create an image just for the config.
+
+.debug[[containers/Logging.md](""/tree/main/slides/containers/Logging.md)]
+---
+
+## Sending logs to ELK
+
+- The ELK stack accepts log messages through a GELF socket.
+
+- The GELF socket listens on UDP port 12201.
+
+- To send a message, we need to change the logging driver used by Docker.
+
+- This can be done globally (by reconfiguring the Engine) or on a per-container basis.
+
+- Let's override the logging driver for a single container:
+
+```bash
+$ docker run --log-driver=gelf --log-opt=gelf-address=udp://localhost:12201 \
+ alpine echo hello world
+```
+
+.debug[[containers/Logging.md](""/tree/main/slides/containers/Logging.md)]
+---
+
+## Viewing the logs in ELK
+
+- Connect to the Kibana interface.
+
+- It is exposed on port 5601.
+
+- Browse http://X.X.X.X:5601.
+
+.debug[[containers/Logging.md](""/tree/main/slides/containers/Logging.md)]
+---
+
+## "Configuring" Kibana
+
+- Kibana should offer you to "Configure an index pattern":
+ in the "Time-field name" drop down, select "@timestamp", and hit the
+ "Create" button.
+
+- Then:
+
+ - click "Discover" (in the top-left corner),
+ - click "Last 15 minutes" (in the top-right corner),
+ - click "Last 1 hour" (in the list in the middle),
+ - click "Auto-refresh" (top-right corner),
+ - click "5 seconds" (top-left of the list).
+
+- You should see a series of green bars (with one new green bar every minute).
+
+- Our 'hello world' message should be visible there.
+
+.debug[[containers/Logging.md](""/tree/main/slides/containers/Logging.md)]
+---
+
+## Important afterword
+
+**This is not a "production-grade" setup.**
+
+It is just an educational example. Since we have only
+one node , we did set up a single
+ElasticSearch instance and a single Logstash instance.
+
+In a production setup, you need an ElasticSearch cluster
+(both for capacity and availability reasons). You also
+need multiple Logstash instances.
+
+And if you want to withstand
+bursts of logs, you need some kind of message queue:
+Redis if you're cheap, Kafka if you want to make sure
+that you don't drop messages on the floor. Good luck.
+
+If you want to learn more about the GELF driver,
+have a look at [this blog post](
+https://jpetazzo.github.io/2017/01/20/docker-logging-gelf/).
+
+.debug[[containers/Logging.md](""/tree/main/slides/containers/Logging.md)]
---
class: pic
-
-
-.debug[[shared/sampleapp.md](""/tree/main/slides/shared/sampleapp.md)]
----
-
-## Service discovery in container-land
-
-How does each service find out the address of the other ones?
-
---
-
-- We do not hard-code IP addresses in the code
-
-- We do not hard-code FQDNs in the code, either
-
-- We just connect to a service name, and container-magic does the rest
-
- (And by container-magic, we mean "a crafty, dynamic, embedded DNS server")
-
-.debug[[shared/sampleapp.md](""/tree/main/slides/shared/sampleapp.md)]
----
-
-## Example in `worker/worker.py`
-
-```python
-redis = Redis("`redis`")
-
-
-def get_random_bytes():
- r = requests.get("http://`rng`/32")
- return r.content
-
-
-def hash_bytes(data):
- r = requests.post("http://`hasher`/",
- data=data,
- headers={"Content-Type": "application/octet-stream"})
-```
-
-(Full source code available [here](
-https://github.com/jpetazzo/container.training/blob/8279a3bce9398f7c1a53bdd95187c53eda4e6435/dockercoins/worker/worker.py#L17
-))
-
-.debug[[shared/sampleapp.md](""/tree/main/slides/shared/sampleapp.md)]
----
-
-class: extra-details
-
-## Links, naming, and service discovery
-
-- Containers can have network aliases (resolvable through DNS)
-
-- Compose file version 2+ makes each container reachable through its service name
-
-- Compose file version 1 required "links" sections to accomplish this
-
-- Network aliases are automatically namespaced
-
- - you can have multiple apps declaring and using a service named `database`
-
- - containers in the blue app will resolve `database` to the IP of the blue database
-
- - containers in the green app will resolve `database` to the IP of the green database
-
-.debug[[shared/sampleapp.md](""/tree/main/slides/shared/sampleapp.md)]
----
-
-## Show me the code!
-
-- You can check the GitHub repository with all the materials of this workshop:
- https://github.com/jpetazzo/container.training
-
-- The application is in the [dockercoins](
- https://github.com/jpetazzo/container.training/tree/master/dockercoins)
- subdirectory
-
-- The Compose file ([docker-compose.yml](
- https://github.com/jpetazzo/container.training/blob/master/dockercoins/docker-compose.yml))
- lists all 5 services
-
-- `redis` is using an official image from the Docker Hub
-
-- `hasher`, `rng`, `worker`, `webui` are each built from a Dockerfile
-
-- Each service's Dockerfile and source code is in its own directory
-
- (`hasher` is in the [hasher](https://github.com/jpetazzo/container.training/blob/master/dockercoins/hasher/) directory,
- `rng` is in the [rng](https://github.com/jpetazzo/container.training/blob/master/dockercoins/rng/)
- directory, etc.)
-
-.debug[[shared/sampleapp.md](""/tree/main/slides/shared/sampleapp.md)]
----
-
-class: extra-details
-
-## Compose file format version
-
-*This is relevant only if you have used Compose before 2016...*
-
-- Compose 1.6 introduced support for a new Compose file format (aka "v2")
-
-- Services are no longer at the top level, but under a `services` section
-
-- There has to be a `version` key at the top level, with value `"2"` (as a string, not an integer)
-
-- Containers are placed on a dedicated network, making links unnecessary
-
-- There are other minor differences, but upgrade is easy and straightforward
-
-.debug[[shared/sampleapp.md](""/tree/main/slides/shared/sampleapp.md)]
----
-
-## Our application at work
-
-- On the left-hand side, the "rainbow strip" shows the container names
-
-- On the right-hand side, we see the output of our containers
-
-- We can see the `worker` service making requests to `rng` and `hasher`
-
-- For `rng` and `hasher`, we see HTTP access logs
-
-.debug[[shared/sampleapp.md](""/tree/main/slides/shared/sampleapp.md)]
----
-
-## Connecting to the web UI
-
-- "Logs are exciting and fun!" (No-one, ever)
-
-- The `webui` container exposes a web dashboard; let's view it
-
-.lab[
-
-- With a web browser, connect to `node1` on port 8000
-
-- Remember: the `nodeX` aliases are valid only on the nodes themselves
-
-- In your browser, you need to enter the IP address of your node
-
-
-
-]
-
-A drawing area should show up, and after a few seconds, a blue
-graph will appear.
-
-.debug[[shared/sampleapp.md](""/tree/main/slides/shared/sampleapp.md)]
----
-
-class: self-paced, extra-details
-
-## If the graph doesn't load
-
-If you just see a `Page not found` error, it might be because your
-Docker Engine is running on a different machine. This can be the case if:
-
-- you are using the Docker Toolbox
-
-- you are using a VM (local or remote) created with Docker Machine
-
-- you are controlling a remote Docker Engine
-
-When you run DockerCoins in development mode, the web UI static files
-are mapped to the container using a volume. Alas, volumes can only
-work on a local environment, or when using Docker Desktop for Mac or Windows.
-
-How to fix this?
-
-Stop the app with `^C`, edit `dockercoins.yml`, comment out the `volumes` section, and try again.
-
-.debug[[shared/sampleapp.md](""/tree/main/slides/shared/sampleapp.md)]
----
-
-class: extra-details
-
-## Why does the speed seem irregular?
-
-- It *looks like* the speed is approximately 4 hashes/second
-
-- Or more precisely: 4 hashes/second, with regular dips down to zero
-
-- Why?
-
---
-
-class: extra-details
-
-- The app actually has a constant, steady speed: 3.33 hashes/second
-
- (which corresponds to 1 hash every 0.3 seconds, for *reasons*)
-
-- Yes, and?
-
-.debug[[shared/sampleapp.md](""/tree/main/slides/shared/sampleapp.md)]
----
-
-class: extra-details
-
-## The reason why this graph is *not awesome*
-
-- The worker doesn't update the counter after every loop, but up to once per second
-
-- The speed is computed by the browser, checking the counter about once per second
-
-- Between two consecutive updates, the counter will increase either by 4, or by 0
-
-- The perceived speed will therefore be 4 - 4 - 4 - 0 - 4 - 4 - 0 etc.
-
-- What can we conclude from this?
-
---
-
-class: extra-details
-
-- "I'm clearly incapable of writing good frontend code!" 😀 — Jérôme
-
-.debug[[shared/sampleapp.md](""/tree/main/slides/shared/sampleapp.md)]
----
-
-## Stopping the application
-
-- If we interrupt Compose (with `^C`), it will politely ask the Docker Engine to stop the app
-
-- The Docker Engine will send a `TERM` signal to the containers
-
-- If the containers do not exit in a timely manner, the Engine sends a `KILL` signal
-
-.lab[
-
-- Stop the application by hitting `^C`
-
-
-
-]
-
---
-
-Some containers exit immediately, others take longer.
-
-The containers that do not handle `SIGTERM` end up being killed after a 10s timeout. If we are very impatient, we can hit `^C` a second time!
-
-
-.debug[[shared/sampleapp.md](""/tree/main/slides/shared/sampleapp.md)]
----
-
-class: pic
-
-.interstitial[]
+.interstitial[]
---
@@ -5826,7 +5227,7 @@ class: title
Links and resources
.nav[
-[Previous part](#toc-our-sample-application)
+[Previous part](#toc-logging)
|
[Back to table of contents](#toc-part-5)
|
diff --git a/slides/intro-fd-k8s-deployments.yml.html b/slides/intro-fd-k8s-deployments.yml.html
index d2f32d0..d2e215e 100644
--- a/slides/intro-fd-k8s-deployments.yml.html
+++ b/slides/intro-fd-k8s-deployments.yml.html
@@ -31,15 +31,13 @@ Introduction to Helm and friends
```
M slides/airgapped/Importing_Images.md
M slides/intro-container-security.yml.html
+ M slides/intro-fd-docker.yml
M slides/intro-fd-docker.yml.html
M slides/intro-fd-k8s-deployments.yml.html
- M slides/swarm-halfday.yml.html
- M slides/swarm-selfpaced.yml.html
- M slides/swarm-video.yml.html
```
-These slides have been built from commit: 65fec64
+These slides have been built from commit: 1e1b023
[shared/title.md](""/tree/main/slides/shared/title.md)]
diff --git a/slides/intro-fd-k8s.yml.html b/slides/intro-fd-k8s.yml.html
index ca869c9..9db0ad6 100644
--- a/slides/intro-fd-k8s.yml.html
+++ b/slides/intro-fd-k8s.yml.html
@@ -31,16 +31,14 @@ Introduction to Kubernetes
```
M slides/airgapped/Importing_Images.md
M slides/intro-container-security.yml.html
+ M slides/intro-fd-docker.yml
M slides/intro-fd-docker.yml.html
M slides/intro-fd-k8s-deployments.yml.html
M slides/intro-fd-k8s.yml.html
- M slides/swarm-halfday.yml.html
- M slides/swarm-selfpaced.yml.html
- M slides/swarm-video.yml.html
```
-These slides have been built from commit: 65fec64
+These slides have been built from commit: 1e1b023
[shared/title.md](""/tree/main/slides/shared/title.md)]
diff --git a/slides/intro-fullday.yml.html b/slides/intro-fullday.yml.html
index f01feaf..4276e94 100644
--- a/slides/intro-fullday.yml.html
+++ b/slides/intro-fullday.yml.html
@@ -31,17 +31,15 @@ Introduction to Containers
```
M slides/airgapped/Importing_Images.md
M slides/intro-container-security.yml.html
+ M slides/intro-fd-docker.yml
M slides/intro-fd-docker.yml.html
M slides/intro-fd-k8s-deployments.yml.html
M slides/intro-fd-k8s.yml.html
M slides/intro-fullday.yml.html
- M slides/swarm-halfday.yml.html
- M slides/swarm-selfpaced.yml.html
- M slides/swarm-video.yml.html
```
-These slides have been built from commit: 65fec64
+These slides have been built from commit: 1e1b023
[shared/title.md](""/tree/main/slides/shared/title.md)]
diff --git a/slides/intro-selfpaced.yml.html b/slides/intro-selfpaced.yml.html
index de9e834..7346925 100644
--- a/slides/intro-selfpaced.yml.html
+++ b/slides/intro-selfpaced.yml.html
@@ -31,18 +31,16 @@ Introduction to Containers
```
M slides/airgapped/Importing_Images.md
M slides/intro-container-security.yml.html
+ M slides/intro-fd-docker.yml
M slides/intro-fd-docker.yml.html
M slides/intro-fd-k8s-deployments.yml.html
M slides/intro-fd-k8s.yml.html
M slides/intro-fullday.yml.html
M slides/intro-selfpaced.yml.html
- M slides/swarm-halfday.yml.html
- M slides/swarm-selfpaced.yml.html
- M slides/swarm-video.yml.html
```
-These slides have been built from commit: 65fec64
+These slides have been built from commit: 1e1b023
[shared/title.md](""/tree/main/slides/shared/title.md)]
diff --git a/slides/intro-triodos-1-day.yml.html b/slides/intro-triodos-1-day.yml.html
index 34d050a..e69de29 100644
--- a/slides/intro-triodos-1-day.yml.html
+++ b/slides/intro-triodos-1-day.yml.html
@@ -1,12233 +0,0 @@
-
-
-
- Triodos Introduction to Containers and orchestration with Kubernetes
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-