You've already forked devops-exercises
Add new exercises
Also added indexes for AWS and Linux.
This commit is contained in:
@@ -1,25 +1,27 @@
|
||||
## Containers
|
||||
# Containers
|
||||
|
||||
### Containers Exercises
|
||||
## Containers Exercises
|
||||
|
||||
|Name|Topic|Objective & Instructions|Solution|Comments|
|
||||
|--------|--------|------|----|----|
|
||||
|Running Containers|Basics|[Exercise](running_containers.md)|[Solution](solutions/running_containers.md)
|
||||
|Containerized Web Server|Basics|[Exercise](containerized_web_server.md)|[Solution](solutions/containerized_web_server.md)
|
||||
|Working with Images|Image|[Exercise](working_with_images.md)|[Solution](solutions/working_with_images.md)
|
||||
|Containerized Web Server|Applications|[Exercise](containerized_web_server.md)|[Solution](solutions/containerized_web_server.md)
|
||||
|Containerized Database|Applications|[Exercise](containerized_db.md)|[Solution](solutions/containerized_db.md)
|
||||
|Containerized Database with Persistent Storage|Applications|[Exercise](containerized_db_persistent_storage.md)|[Solution](solutions/containerized_db_persistent_storage.md)
|
||||
|My First Dockerfile|Dockerfile|[Exercise](write_dockerfile_run_container.md)|
|
||||
|Run, Forest, Run!|Restart Policies|[Exercise](run_forest_run.md)|[Solution](solutions/run_forest_run.md)
|
||||
|Layer by Layer|Image Layers|[Exercise](image_layers.md)|[Solution](solutions/image_layers.md)
|
||||
|Containerize an application | Containerization |[Exercise](containerize_app.md)|[Solution](solutions/containerize_app.md)
|
||||
|Multi-Stage Builds|Multi-Stage Builds|[Exercise](multi_stage_builds.md)|[Solution](solutions/multi_stage_builds.md)
|
||||
|
||||
### Containers Self Assessment
|
||||
## Containers Self Assessment
|
||||
|
||||
* [Containers 101](#questions-containers-101)
|
||||
* [OCI](#questions-oci)
|
||||
* [Images](#questions-images)
|
||||
* [Basic Commands](#questions-basic-commands)
|
||||
* [Volume](#questions-volume)
|
||||
* [Storage](#questions-containers-storage)
|
||||
* [Dockerfile](#questions-dockerfile)
|
||||
* [Architecture](#questions-architecture)
|
||||
* [Docker Architecture](#questions-docker-architecture)
|
||||
@@ -29,9 +31,10 @@
|
||||
* [Docker Networking](#questions-docker-networking)
|
||||
* [Security](#questions-security)
|
||||
* [Docker In Production](#questions-docker-in-production)
|
||||
* [Rootless Containers](#questions-rootless-containers)
|
||||
|
||||
<a name="questions-containers-101"></a>
|
||||
#### Containers 101
|
||||
### Containers 101
|
||||
|
||||
<details>
|
||||
<summary>What is a Container?</summary><br><b>
|
||||
@@ -98,7 +101,7 @@ You should choose containers when:
|
||||
</b></details>
|
||||
|
||||
<a name="questions-oci"></a>
|
||||
#### Containers - OCI
|
||||
### OCI
|
||||
|
||||
<details>
|
||||
<summary>What is the OCI?</summary><br><b>
|
||||
@@ -118,7 +121,7 @@ Create, Kill, Delete, Start and Query State.
|
||||
</b></details>
|
||||
|
||||
<a name="questions-images"></a>
|
||||
#### Containers - Images
|
||||
### Images
|
||||
|
||||
<details>
|
||||
<summary>What is a container image?</summary><br><b>
|
||||
@@ -154,7 +157,7 @@ docker.io docker.io/rahulgadre/snake-game
|
||||
<details>
|
||||
<summary>How to list the container images on certain host?</summary><br><b>
|
||||
|
||||
CONTAINER_BINARY=podman # or docker
|
||||
CONTAINER_BINARY=podman
|
||||
$CONTAINER_BINARY images
|
||||
```
|
||||
|
||||
@@ -165,7 +168,7 @@ Note: you can also use `$CONTAINER_RUNTIME image ls`
|
||||
<summary>How to download/pull a container image without actually running a container?</summary><br><b>
|
||||
|
||||
```
|
||||
CONTAINER_BINARY=podman # or docker
|
||||
CONTAINER_BINARY=podman
|
||||
$CONTAINER_BINARY pull rhel
|
||||
```
|
||||
</b></details>
|
||||
@@ -375,7 +378,7 @@ Cons:
|
||||
</b></details>
|
||||
|
||||
<a name="questions-basic-commands"></a>
|
||||
#### Containers - Basic Commands
|
||||
### Basic Commands
|
||||
|
||||
<details>
|
||||
<summary>How to list all the containers on a given host?</summary><br><b>
|
||||
@@ -437,18 +440,73 @@ With the -d flag. It will run in the background and will not attach it to the te
|
||||
`docker container run -d httpd` or `podman container run -d httpd`
|
||||
</b></details>
|
||||
|
||||
<details>
|
||||
<summary>If you'll run <code>sleep 100</code> inside a container, will you see it when listing all the processes of the host on which the container runs? Why?</summary><br><b>
|
||||
</b></details>
|
||||
|
||||
<a name="questions-volume"></a>
|
||||
#### Containers - Volume
|
||||
<details>
|
||||
<summary>True or False? If image <code>httpd-service</code> has an entry point for running the httpd service then, the following will run the container and eventually the httpd service <code>podman run httpd-service ls</code></summary><br><b>
|
||||
|
||||
False. Running that command will override the entry point so the httpd service won't run and instead podman will run the `ls` command.
|
||||
</b></details>
|
||||
|
||||
<details>
|
||||
<summary>True or False? Running <code>podman restart CONTAINER_NAME</code> kills the main process inside the container and runs it again from scratch</summary><br><b>
|
||||
|
||||
False. `podman restart` creates an entirely new container with the same ID while reusing the filesystem and state of the original container.
|
||||
</b></details>
|
||||
|
||||
<a name="questions-containers-storage"></a>
|
||||
### Storage
|
||||
|
||||
<details>
|
||||
<summary>Container storage is said to be ephemeral. What does it mean?</summary><br><b>
|
||||
|
||||
It means the contents of the container and the data generated by it, is gone when the container is removed.
|
||||
</b></details>
|
||||
|
||||
<details>
|
||||
<summary>True or False? Applications running on containers, should use the container storage to store persistent data</summary><br><b>
|
||||
|
||||
False. Containers are not built to store persistent data and even if it's possible with some implementations, it might not perform well in case of applications with intensive I/O operations.
|
||||
</b></details>
|
||||
|
||||
<details>
|
||||
<summary>You stopped a running container but, it still uses the storage in case you ever resume it. How to reclaim the storage of a container?</summary><br><b>
|
||||
|
||||
In order to reclaim the storage of a container, you have to remove it.
|
||||
</b></details>
|
||||
|
||||
<details>
|
||||
<summary>How to create a new volume?</summary><br><b>
|
||||
|
||||
`docker volume create some_volume`
|
||||
```
|
||||
CONTAINER_BINARY=podman
|
||||
$CONTAINER_BINARY volume create some_volume
|
||||
```
|
||||
</b></details>
|
||||
|
||||
<details>
|
||||
<summary>How to mount a directory from the host to a container?</summary><br><b>
|
||||
|
||||
```
|
||||
CONTAINER_BINARY=podman
|
||||
mkdir /tmp/dir_on_the_host
|
||||
|
||||
$CONTAINER_BINARY run -v /tmp/dir_on_the_host:/tmp/dir_on_the_container IMAGE_NAME
|
||||
```
|
||||
|
||||
In some systems you'll have also to adjust security on the host itself:
|
||||
|
||||
```
|
||||
podman unshare chown -R UID:GUID /tmp/dir_on_the_host
|
||||
sudo semanage fcontext -a -t container_file_t '/tmp/dir_on_the_host(/.*)?'
|
||||
sudo restorecon -Rv /tmp/dir_on_the_host
|
||||
```
|
||||
</b></details>
|
||||
|
||||
<a name="questions-dockerfile"></a>
|
||||
#### Containers - Dockerfile
|
||||
### Dockerfile
|
||||
|
||||
<details>
|
||||
<summary>What is a Dockerfile?</summary><br><b>
|
||||
@@ -539,7 +597,7 @@ Instructions such as ENTRYPOINT, ENV, EXPOSE, create image metadata and they don
|
||||
</b></details>
|
||||
|
||||
<a name="questions-architecture"></a>
|
||||
#### Containers - Architecture
|
||||
### Architecture
|
||||
|
||||
<details>
|
||||
<summary>How container achieve isolation from the rest of the system?</summary><br><b>
|
||||
@@ -613,8 +671,14 @@ Multiple namespaces: pid,net, mnt, uts, ipc, user
|
||||
* SElinux
|
||||
</b></details>
|
||||
|
||||
<details>
|
||||
<summary>True or False? Containers have ephemeral storage layer</summary><br><b>
|
||||
|
||||
True. The ephemeral storage layer is added on top of the base image layer and is exclusive to the running container. This way, containers created from the same base image, don't share the same storage.
|
||||
</b></details>
|
||||
|
||||
<a name="questions-docker-architecture"></a>
|
||||
#### Containers - Docker Architecture
|
||||
### Docker Architecture
|
||||
|
||||
<details>
|
||||
<summary>Which components/layers compose the Docker technology?</summary><br><b>
|
||||
@@ -791,7 +855,7 @@ Because each container has its own writable container layer, and all changes are
|
||||
</b></details>
|
||||
|
||||
<a name="questions-docker-compose"></a>
|
||||
#### Containers - Docker Compose
|
||||
### Docker Compose
|
||||
|
||||
<details>
|
||||
<summary>Explain what is Docker compose and what is it used for</summary><br><b>
|
||||
@@ -810,7 +874,7 @@ In general, it's useful for running applications which composed out of several d
|
||||
</b></details>
|
||||
|
||||
<a name="questions-docker-images"></a>
|
||||
#### Containers - Docker Images
|
||||
### Docker Images
|
||||
|
||||
<details>
|
||||
<summary>What is Docker Hub?</summary><br><b>
|
||||
@@ -867,7 +931,7 @@ By default, Docker uses everything (all the files and directories) in the direct
|
||||
</b></details>
|
||||
|
||||
<a name="questions-networking"></a>
|
||||
#### Containers - Networking
|
||||
### Networking
|
||||
|
||||
<details>
|
||||
<summary>What container network standards or architectures are you familiar with?</summary><br><b>
|
||||
@@ -880,7 +944,7 @@ CNI (Container Network Interface):
|
||||
</b></details>
|
||||
|
||||
<a name="questions-docker-networking"></a>
|
||||
#### Containers - Docker Networking
|
||||
### Docker Networking
|
||||
|
||||
<details>
|
||||
<summary>What network specification Docker is using and how its implementation is called?</summary><br><b>
|
||||
@@ -916,7 +980,7 @@ True. An endpoint can connect only to a single network.
|
||||
</b></details>
|
||||
|
||||
<a name="questions-security"></a>
|
||||
#### Containers - Security
|
||||
### Security
|
||||
|
||||
<details>
|
||||
<summary>What security best practices are there regarding containers?</summary><br><b>
|
||||
@@ -937,7 +1001,7 @@ True. An endpoint can connect only to a single network.
|
||||
</b></details>
|
||||
|
||||
<a name="questions-docker-in-production"></a>
|
||||
#### Containers - Docker in Production
|
||||
### Docker in Production
|
||||
|
||||
<details>
|
||||
<summary>What are some best practices you following in regards to using containers in production?</summary><br><b>
|
||||
@@ -973,3 +1037,44 @@ Restart Policies. It allows you to automatically restart containers after certai
|
||||
* no: don't restart the container at any point (default policy)
|
||||
* on-failure: restart the container when it exists due to an error (= exit code different than zero)
|
||||
</b></details>
|
||||
|
||||
<a name="questions-rootless-containers"></a>
|
||||
|
||||
<details>
|
||||
<summary>Explain Rootless Containers</summary><br><b>
|
||||
|
||||
Historically, user needed root privileges to run containers. One of the most basic security recommendations is to provide users with minimum privileges for what they need.
|
||||
|
||||
For containers it's been the situation for a long time and still for running some containers today from docker.io, you'll need to have root privileges.
|
||||
</b></details>
|
||||
|
||||
<details>
|
||||
<summary>Are there disadvantages in running rootless containers?</summary><br><b>
|
||||
|
||||
Yes, the full list can be found [here](https://github.com/containers/podman/blob/main/rootless.md).
|
||||
|
||||
Some worth to mention:
|
||||
|
||||
- No binding to ports smaller than 1024
|
||||
- No images sharing CRI-O or other rootful users
|
||||
- No support running on NFS or parallel filesystem homerdirs
|
||||
- Some commands don't work (mount, podman stats, checkpoint, restore, ...)
|
||||
</b></details>
|
||||
|
||||
<details>
|
||||
<summary>Give one example of rootless containers are more safe from security perspective</summary><br><b>
|
||||
|
||||
In rootless containers, user namespace appears to be running as root but it doesn't, it's executed with regular user privileges. If an attacker manages to get out of the user space to the host with the same privileges, there's not much he can do because it's not root privileges as opposed to containers that run with root privileges.
|
||||
</b></details>
|
||||
|
||||
<details>
|
||||
<summary>When running a container, usually a virtual ethernet device is created. To do so, root privileges are required. How is it then managed in rootless containers?</summary><br><b>
|
||||
|
||||
Networking is usually managed by Slirp in rootless containers. Slirp creates a tap device which is also the default route and it creates it in the network namepsace of the container. This device's file descriptor passed to the parent who runs it in the default namespace and the default namespace connected to the internet. This enables communication externally and internally.
|
||||
</b></details>
|
||||
|
||||
<details>
|
||||
<summary>When running a container, usually a layered file system is created, but it requires root privileges. How is it then managed in rootless containers?</summary><br><b>
|
||||
|
||||
New drivers were created to allow creating filesystems in a user namespaces. Drivers like the FUSE-OverlayFS.
|
||||
</b></details>
|
||||
|
||||
9
exercises/containers/containerized_db.md
Normal file
9
exercises/containers/containerized_db.md
Normal file
@@ -0,0 +1,9 @@
|
||||
## Containerized DB
|
||||
|
||||
1. Run a container with a database of any type of you prefer (MySql, PostgreSQL, Mongo, etc.)
|
||||
2. Verify the container is running
|
||||
3. Access the container and create a new table (or collection, depends on which DB type you chose) for students
|
||||
4. Insert a row (or document) of a student
|
||||
5. Verify the row/document was added
|
||||
|
||||
Click [here for the solution](solutions/containerized_db.md)
|
||||
@@ -0,0 +1,6 @@
|
||||
# Containerized DB with Persistent Storage
|
||||
|
||||
1. Run a container with a database of any type of you prefer (MySql, PostgreSQL, Mongo, etc.)
|
||||
1. Use a mount point on the host for the database instead of using the container storage for that
|
||||
2. Explain why using the host storage instead of the container one might be a better choice
|
||||
2. Verify the container is running
|
||||
@@ -3,3 +3,5 @@
|
||||
1. Run a containerized web server in the background and bind its port (8080) to a local port
|
||||
2. Verify the port (8080) is bound
|
||||
3. Reach the webserver from your local host
|
||||
|
||||
Click [here for the solution](solutions/containerized_web_server.md)
|
||||
|
||||
26
exercises/containers/solutions/containerized_db.md
Normal file
26
exercises/containers/solutions/containerized_db.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Containerized DB
|
||||
|
||||
1. Run a container with a database of any type of you prefer (MySql, PostgreSQL, Mongo, etc.)
|
||||
2. Verify the container is running
|
||||
3. Access the container and create a new table (or collection, depends on which DB type you chose) for students
|
||||
4. Insert a row (or document) of a student
|
||||
5. Verify the row/document was added
|
||||
|
||||
|
||||
## Solution
|
||||
|
||||
```
|
||||
# Run the container
|
||||
podman run --name mysql -e MYSQL_USER=mario -e MYSQL_PASSWORD=tooManyMushrooms -e MYSQL_DATABASE=university -e MYSQL_ROOT_PASSWORD=MushroomsPizza -d mysql
|
||||
|
||||
# Verify it's running
|
||||
podman ps
|
||||
|
||||
# Add student row to the database
|
||||
podman exec -it mysql /bin/bash
|
||||
mysql -u root
|
||||
use university;
|
||||
CREATE TABLE Students (id int NOT NULL, name varchar(255) DEFAULT NULL, PRIMARY KEY (id));
|
||||
insert into Projects (id, name) values (1,'Luigi');
|
||||
select * from Students;
|
||||
```
|
||||
@@ -0,0 +1,24 @@
|
||||
# Containerized DB with Persistent Storage
|
||||
|
||||
1. Run a container with a database of any type of you prefer (MySql, PostgreSQL, Mongo, etc.)
|
||||
1. Use a mount point on the host for the database instead of using the container storage for that
|
||||
2. Explain why using the host storage instead of the container one might be a better choice
|
||||
2. Verify the container is running
|
||||
|
||||
|
||||
## Solution
|
||||
|
||||
```
|
||||
# Create the directory for the DB on host
|
||||
mkdir -pv ~/local/mysql
|
||||
sudo semanage fcontext -a -t container_file_t '/home/USERNAME/local/mysql(/.*)?'
|
||||
sudo restorecon -R /home/USERNAME/local/mysql
|
||||
|
||||
# Run the container
|
||||
podman run --name mysql -e MYSQL_USER=mario -e MYSQL_PASSWORD=tooManyMushrooms -e MYSQL_DATABASE=university -e MYSQL_ROOT_PASSWORD=MushroomsPizza -d mysql -v /home/USERNAME/local/mysql:/var/lib/mysql/db
|
||||
|
||||
# Verify it's running
|
||||
podman ps
|
||||
```
|
||||
|
||||
It's better to use the storage host because in case the container ever gets removed (or storage reclaimed) you have the DB data still available.
|
||||
Reference in New Issue
Block a user