Rename exercises dir

Name it instead "topics" so it won't be
strange if some topics included "exercises" directory.
This commit is contained in:
abregman
2022-08-02 01:51:39 +03:00
parent ea1d94d67b
commit 99c4e02ecf
235 changed files with 283 additions and 74 deletions

1279
topics/containers/README.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,36 @@
# Create Images on The Fly
## Requirements
Have at least one image locally (run `podman image ls` to confirm).<br>
If you don't have images locally, run simply `podman pull nginx:alpine`.
## Objectives
1. Run a container using a web server image (e.g. httpd, nginx, ...)
- Bind container's port 80 to local port 80
- Run it in detached mode
- Name should nginx_container
2. Verify the web server runs and accessible
3. Create an HTML file with the following content and copy it to the container to the container to path where it will be accessed as an index file
```
<html>
<head>
<title>It's a me</title>
</head>
<body>
<h1>Mario</h1>
</body>
```
4. Create an image out of the running container and call it "nginx_mario"
5. Tag the container with "mario" tag
6. Remove the original container (container_nginx) and verify it was removed
7. Create a new container out of the image you've created (the same way as the original container)
8. Run `curl 127.0.0.1:80`. What do you see?
9. Run `podman diff` on the new image. Explain the output
## Solution
Click [here to view the solution](solutions/commit_image.md)

View 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)

View File

@@ -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

View File

@@ -0,0 +1,8 @@
# Containerized Web Server
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
4. Now run the same web application but bound it to the local port 8080
Click [here for the solution](solutions/containerized_web_server.md)

View File

@@ -0,0 +1,23 @@
## Layer by Layer
### Objective
Learn about image layers
### Requirements
Make sure Docker is installed on your system and the service is started
```
# Fedora/RHEL/CentOS
rpm -qa | grep docker
systemctl status docker
```
### Instructions
1. Write a Dockefile. Any Dockefile! :) (just make sure it's a valid one)
2. Build an image using the Dockerfile you've wrote
3. Which of the instructions you've used, created new layers and which added image metadata?
4. What ways are there to confirm your answer to the last question?
5. Can you reduce the size of the image you've created?

View File

@@ -0,0 +1,31 @@
## Multi-Stage Builds
### Objective
Learn about multi-stage builds
### Instructions
1. Without actually building an image or running any container, use the following Dockerfile and convert it to use multi-stage:
```
FROM nginx
RUN apt-get update \
&& apt-get install -y curl python build-essential \
&& apt-get install -y nodejs \
&& apt-get clean -y
RUN mkdir -p /my_app
ADD ./config/nginx/docker.conf /etc/nginx/nginx.conf
ADD ./config/nginx/k8s.conf /etc/nginx/nginx.conf.k8s
ADD app/ /my_cool_app
WORKDIR /my_cool_app
RUN npm install -g ember-cli
RUN npm install -g bower
RUN apt-get update && apt-get install -y git \
&& npm install \
&& bower install \
RUN ember build — environment=prod
CMD [ “/root/nginx-app.sh”, “nginx”, “-g”, “daemon off;” ]
```
2. What are the benefits of using multi-stage builds?

View File

@@ -0,0 +1,31 @@
## Run, Forest, Run!
### Objective
Learn what restart policies do and how to use them
### Requirements
Make sure Docker is installed on your system and the service is started
```
# Fedora/RHEL/CentOS
rpm -qa | grep docker
systemctl status docker
```
### Instructions
1. Run a container with the following properties:
* image: alpine
* name: forest
* restart policy: always
* command to execute: sleep 15
2. Run `docker container ls` - Is the container running? What about after 15 seconds, is it still running? why?
3. How then can we stop the container from running?
4. Remove the container you've created
5. Run the same container again but this time with `sleep 600` and verify it runs
6. Restart the Docker service. Is the container still running? why?
8. Update the policy to `unless-stopped`
9. Stop the container
10. Restart the Docker service. Is the container running? why?

View File

@@ -0,0 +1,18 @@
## Running Containers
### Objective
Learn how to run, stop and remove containers
### Requirements
Make sure Podman or Docker (or any other containers engine) is installed on your system
### Instructions
1. Run a container using the latest nginx image
2. List the containers to make sure the container is running
3. Run another container but this time use ubuntu latest and attach to the terminal of the container
4. List again the containers. How many containers are running?
5. Stop the containers
6. Remove the containers

View File

@@ -0,0 +1,18 @@
# Sharing Images
## Requirements
Have at least one image locally (run `podman image ls` to confirm).<br>
If you don't have images locally, run simply `podman pull httpd`.
## Objectives
1. Choose an image and create an archive out of it
2. Check the archive size. Is it different than the image size? If yes, what's the difference? If not, why?
3. Copy the generated archive to a remote host
4. Load the image
5. Verify it was loaded and exists on the remote host
## Solution
Click [here to view the solution](solutions/sharing_images.md)

View File

@@ -0,0 +1,107 @@
# Create Images on The Fly
## Requirements
Have at least one image locally (run `podman image ls` to confirm).<br>
If you don't have images locally, run simply `podman pull nginx:alpine`.
## Objectives
1. Run a container using a web server image (e.g. httpd, nginx, ...)
- Bind container's port 80 to local port 80
- Run it in detached mode
- Name should nginx_container
2. Verify the web server runs and accessible
3. Create an HTML file with the following content and copy it to the container to the container to path where it will be accessed as an index file
```
<html>
<head>
<title>It's a me</title>
</head>
<body>
<h1>Mario</h1>
</body>
```
4. Create an image out of the running container and call it "nginx_mario"
5. Tag the container with "mario" tag
6. Remove the original container (container_nginx) and verify it was removed
7. Create a new container out of the image you've created (the same way as the original container)
8. Run `curl 127.0.0.1:80`. What do you see?
9. Run `podman diff` on the new image. Explain the output
## Solution
```
# Run the container
podman run --name nginx_container -d -p 80:80 nginx:alpine
# Verify web server is running
curl 127.0.0.1:80
# <!DOCTYPE html>
# <html>
# <head>
# <title>Welcome to nginx!</title>
# Create index.html file
cat <<EOT >>index.html
<html>
<head>
<title>It's a me</title>
</head>
<body>
<h1>Mario</h1>
</body>
EOT
# Copy index.html to the container
podman cp index.html nginx_container:/usr/share/nginx/html/index.html
# Create a new image out of the running container
podman commit nginx_container nginx_mario
# Tag the image
podman image ls
# localhost/nginx_mario latest dc7ed2343521 52 seconds ago 25 MB
podman tag dc7ed2343521 mario
# Remove the container
podman stop nginx_container
podman rm nginx_container
podman ps -a # no container 'nginx_container'
# Create a container out of the image
podman run -d -p 80:80 nginx_mario
# Check the container created from the new image
curl 127.0.0.1:80
#<html>
#<head>
#<title>It's a me</title>
#</head>
#<body>
#<h1>Mario</h1>
#</body>
# Run diff
podman diff nginx_mario
C /etc
C /etc/nginx/conf.d
C /etc/nginx/conf.d/default.conf
A /run/nginx.pid
C /usr/share/nginx/html
C /usr/share/nginx/html/index.html
C /var/cache/nginx
C /var
C /var/cache
A /var/cache/nginx/client_temp
A /var/cache/nginx/fastcgi_temp
A /var/cache/nginx/proxy_temp
A /var/cache/nginx/scgi_temp
A /var/cache/nginx/uwsgi_temp
# We've set new index.html which explains why it's changed (C)
# We also created the image while the web server is running, which explains all the files created under /var
```

View 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;
```

View File

@@ -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.

View File

@@ -0,0 +1,24 @@
# Containerized Web Server
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
4. Now run the same web application but bound it to the local port 8080
## Solution
```
$ podman run -d -p 8080 httpd # run the container and bind the port 8080 to a local port
$ podman port -l 8080 # show to which local port the port 8080 on the container, binds to
0.0.0.0:41203
$ curl http://0.0.0.0:41203 # use the port from the output of the previous command
!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Test Page for the HTTP Server on Red Hat Enterprise Linux</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
$ podman run -d -p 8080:8080 httpd
```

View File

@@ -0,0 +1,54 @@
## Layer by Layer
### Objective
Learn about image layers
### Requirements
Make sure Docker is installed on your system and the service is started
```
# Fedora/RHEL/CentOS
rpm -qa | grep docker
systemctl status docker
```
### Instructions
1. Write a Dockefile. Any Dockefile! :) (just make sure it's a valid one)
```
FROM ubuntu
EXPOSE 212
ENV foo=bar
WORKDIR /tmp
RUN dd if=/dev/zero of=some_file bs=1024 count=0 seek=1024
RUN dd if=/dev/zero of=some_file bs=1024 count=0 seek=1024
RUN dd if=/dev/zero of=some_file bs=1024 count=0 seek=1024
```
2. Build an image using the Dockerfile you've wrote
`docker image build -t super_cool_app:latest .`
3. Which of the instructions you've used, created new layers and which added image metadata?
```
FROM, RUN -> new layer
EXPOSE, ENV, WORKDIR -> metadata
```
4. What ways are there to confirm your answer to the last question?
You can run `docker image history super_cool_app`. It will show you each instruction and its size. Usually instructions that create new layers has non-zero size, but this is not something you can rely on by itself since, some run commands can have size of zero in `docker image history` output (e.g. `ls -l`).
You can also use `docker image inspect super_cool_appl` and see if in the output, under "RootFS", there are the number of layers that matches the instructions that should create new layers.
5. Can you reduce the size of the image you've created?
yes, for example, use all the RUN instructions as a single RUN instruction this way:
`RUN dd if=/dev/zero of=some_file bs=1024 count=0 seek=1024 && dd if=/dev/zero of=some_file bs=1024 count=0 seek=1024 && dd if=/dev/zero of=some_file bs=1024 count=0 seek=1024`
The change in size might not be dramatic in this case, but in some cases it will make a big impact on the image size.

View File

@@ -0,0 +1,58 @@
## Multi-Stage Builds
### Objective
Learn about multi-stage builds
### Instructions
1. Without actually building an image or running any container, use the following Dockerfile and convert it to use multi-stage:
```
FROM nginx
RUN apt-get update \
&& apt-get install -y curl python build-essential \
&& apt-get install -y nodejs \
&& apt-get clean -y
RUN mkdir -p /my_app
ADD ./config/nginx/docker.conf /etc/nginx/nginx.conf
ADD ./config/nginx/k8s.conf /etc/nginx/nginx.conf.k8s
ADD app/ /my_cool_app
WORKDIR /my_cool_app
RUN npm install -g ember-cli
RUN npm install -g bower
RUN apt-get update && apt-get install -y git \
&& npm install \
&& bower install \
RUN ember build — environment=prod
CMD [ “/root/nginx-app.sh”, “nginx”, “-g”, “daemon off;” ]
```
2. What are the benefits of using multi-stage builds?
### Solution
1. One possible solution (the emphasize is on passing the app from the first stage):
```
FROM node:6
RUN mkdir -p /my_cool_app
RUN npm install -g ember-cli
RUN npm install -g bower
WORKDIR /my_cool_app
RUN npm install
ADD app/ /my_cool_app
RUN bower install
RUN ember build — environment=prod
FROM nginx
RUN mkdir -p /my_cool_app
ADD ./config/nginx/docker.conf /etc/nginx/nginx.conf
ADD ./config/nginx/k8s.conf /etc/nginx/nginx.conf.k8s
# Copy build artifacts from the first stage
COPY — from=0 /my_cool_app/dist /my_cool_app/dist
WORKDIR /my_cool_app
CMD [ “/root/nginx-app.sh”, “nginx”, “-g”, “daemon off;” ]
```
2. Multi-stages builds allow you to produce smaller container images by splitting the build process into multiple stages as we did above. The app image doesn't contain anything related to the build process except the actual app.

View File

@@ -0,0 +1,71 @@
## Run, Forest, Run!
### Objective
Learn what restart policies do and how to use them
### Requirements
Make sure Docker is installed on your system and the service is started
```
# Fedora/RHEL/CentOS
rpm -qa | grep docker
systemctl status docker
```
### Instructions
1. Run a container with the following properties:
* image: alpine
* name: forest
* restart policy: always
* command to execute: sleep 15
`docker run --restart always --name forest alpine sleep 15`
2. Run `docker container ls` - Is the container running? What about after 15 seconds, is it still running? why?
It runs even after it completes to run `sleep 15` because the restart policy is "always". This means that Docker will keep restarting the **same** container even after it exists.
3. How then can we stop the container from running?
The restart policy doesn't apply when the container is stopped with the command `docker container stop`
4. Remove the container you've created
```
docker container stop forest
docker container rm forest
```
5. Run the same container again but this time with `sleep 600` and verify it runs
```
docker run --restart always --name forest alpine sleep 600
docker container ls
```
6. Restart the Docker service. Is the container still running? why?
```
sudo systemctl restart docker
```
Yes, it's still running due to the restart policy `always` which means Docker will always bring up the container after it exists or stopped (not with the stop command).
8. Update the policy to `unless-stopped`
`docker update --restart unless-stopped forest`
9. Stop the container
`docker container stop forest`
10. Restart the Docker service. Is the container running? why?
```
sudo systemctl restart docker
```
No, the container is not running. This is because we changed the policy to `unless-stopped` which will run the container unless it was in stopped status. Since before the restart we stopped the container, Docker didn't continue running it after the restart.

View File

@@ -0,0 +1,18 @@
## Running Containers
### Objective
Learn how to run, stop and remove containers
### Requirements
Make sure Podman or Docker (or any other containers engine) is installed on your system
### Instructions
1. Run a container using the latest nginx image - `podman container run nginx:latest`
2. List the containers to make sure the container is running - `podman container ls`
3. Run another container but this time use ubuntu latest and attach to the terminal of the container - `podman container run -it ubuntu:latest /bin/bash`
4. List again the containers. How many containers are running? - `podman container ls` -> 2
5. Stop the containers - WARNING: the following will stop all the containers on the host: `podman stop $(podman container ls -q)` or for each container `podman stop [container id/name]`
6. Remove the containers - WARNING: the following will remove other containers as well if such are running: `podman rm $(podman container ls -q -a)` or for each container `podman rm [container id/name]`

View File

@@ -0,0 +1,35 @@
# Sharing Images
## Requirements
Have at least one image locally (run `podman image ls` to confirm).<br>
If you don't have images locally, run simply `podman pull httpd`.
## Objectives
1. Choose an image and create an archive out of it
2. Check the archive size. Is it different than the image size? If yes, what's the difference? If not, why?
3. Copy the generated archive to a remote host
4. Load the image
5. Verify it was loaded and exists on the remote host
## Solution
```
# Save image as an archive
podman save -o httpd.tar httpd
# Check archive and image sizes
du -sh httpd.tar # output: 143MB
podman image ls | grep httpd # output: 149MB
# The archive is obviously smaller than the image itself (6MB difference)
# Copy the archive to a remote host
rsync -azc httpd.tar USER@REMOTE_HOST_FQDN:/tmp/
# Load the image
podman load -i /tmp/httpd.tar
# Verify it exists on the system after loading
podman image ls
```

View File

@@ -0,0 +1,17 @@
## Working with Images - Solution
### Objective
Learn how to work with containers images
### Requirements
Make sure Podman, Docker (or any other containers engine) is installed on your system
### Instructions
1. List the containers images in your environment - `podman image ls`
2. Pull the latest ubuntu image - `podman image pull ubuntu:latest`
3. Run a container with the image you just pulled - `podman container run -it ubuntu:latest /bin/bash`
4. Remove the image. Did it work? - No. There is a running container which is using the image we try to remove
5. Do whatever is needed in order to remove the image - `podman rm <container_id>; podman image rm ubuntu`

View File

@@ -0,0 +1,17 @@
## Working with Images
### Objective
Learn how to work with containers images
### Requirements
Make sure Podman or Docker (or any other containers engine) is installed on your system
### Instructions
1. List the containers images in your environment
2. Pull the latest ubuntu image
3. Run a container with the image you just pulled
4. Remove the image. Did it work?
5. Do whatever is needed in order to remove the image

View File

@@ -0,0 +1,11 @@
# Write a Containerfile and run a container
## Objectives
1. Create a Docker image:
* Use centos or ubuntu as the base image
* Install apache web server
* Deploy any web application you want
* Add https support (using HAProxy as reverse-proxy)
2. Once you wrote the Containerfile and created an image, run the container and test the application. Describe how did you test it and provide output
3. Describe one or more weakness of your Containerfile. Is it ready to be used in production?