Docker Fundamental
**Tittle 1: Introduction to Docker**
-
**1. What is Containerization?**
Containerization is a software deployment process that bundles application code with all the files and libraries needed to run on any infrastructure. Traditionally, to run any application on a computer, you have to install a version that matches your machine's operating system. For example, you need to install a Windows version of a software package on a Windows machine. However, with containerization, you can create a single software package, or container, that runs on all types of devices and operating systems.
**2. Various application deployment architectures**

As you can see, for a Traditional Deployment we have three applications, all sharing the same software stack. Running virtual machines allow us to run three applications, running two completely different software stacks. This diagram gives us a lot of insight into the biggest key benefit of Docker, that is, there is no need for a complete operating system every time we need to bring up a new container, which cuts down on the overall size of containers. Since almost all the versions of Linux use the standard kernel models, Docker relies on using the host operating system's Linux kernel for the operating system it was built upon, such as Red Hat, CentOS, and Ubuntu.
**3. What is Docker?**

Docker is an open platform for developing, shipping, and running applications. Docker enables you to separate your applications from your infrastructure so you can deliver software quickly. With Docker, you can manage your infrastructure in the same ways you manage your applications. By taking advantage of Docker’s methodologies for shipping, testing, and deploying code quickly, you can significantly reduce the delay between writing code and running it in production.
**4. Alternative runtime for Container use**
- **Podman**

Podman is a daemonless, open source, Linux native tool designed to make it easy to find, run, build, share and deploy applications using Open Containers Initiative (OCI) Containers and Container Images. Podman provides a command line interface (CLI) familiar to anyone who has used the Docker Container Engine. Most users can simply alias Docker to Podman (alias docker=podman) without any problems. Similar to other common Container Engines (Docker, CRI-O, containerd), Podman relies on an OCI compliant Container Runtime (runc, crun, runv, etc) to interface with the operating system and create the running containers. This makes the running containers created by Podman nearly indistinguishable from those created by any other common container engine.
- **Containerd**

Containerd in simple terms is a container runtime that is, Containerd is a software responsible for running and managing containers on a host system. It is a resource manager which manages the container processes, image, snapshots, container metadata and its dependencies. Going further, Containerd is a daemon for Linux and Windows, that manages the complete container life cycle of its host system from image transfer and storage to container execution and supervision and beyond. So basically Containerd is a complete package for the container lifecycle. Containerd is a CNCF (Cloud Native Community Foundation) graduated project. It was the fifth project to graduate from CNCF on 2019. In this article we will learn about Containerd and why it is consider the secret hero of the cloud native world.
**Tittle 2: Try Docker Deployment**
-
**1. Getting started with docker**
- **Docker Architecture**

**Docker daemon** functions to build, distribute and run Docker containers. Users cannot directly use the Docker Daemon, but to use the Docker Daemon the user uses the Docker client as an intermediary or CLI.
**Docker images** are read only templates. This template is actually an OS or OS that has various applications installed. Docker images function to create docker containers, with just 1 docker image we can create many docker containers.
**Docker container** can be said to be a folder, where the Docker container is created using the Docker daemon. Every time a Docker container is saved, a new layer will be formed right above the Docker image or base image above it. For example, let's say we use an Ubuntu image, then we create a container from the Ubuntu image with the name ubuntuu, then we install software such as nginx, then automatically the Ubuntu container will be above the image layer or base Ubuntu image. You can create multiple docker containers from 1 docker image. This Docker container can later be built so that it will produce a Docker image, and we can reuse the Docker images produced from this Docker container to create a new Docker container.
**Docker registry** is a collection of private and public docker images that you can access on Docker Hub. By using the docker registry, you can use docker images that have been created by other developers, making it easier for us to develop applications.
- **Install Docker**
**Execute in all node**
```bash
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg lsb-release -y
sudo mkdir -m 0755 -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
```
- **Display docker version**
```bash
student@pod-sandy8-node01:~$ docker version
Client: Docker Engine - Community
Version: 26.0.0
API version: 1.45
Go version: go1.21.8
Git commit: 2ae903e
Built: Wed Mar 20 15:17:48 2024
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 26.0.0
API version: 1.45 (minimum version 1.24)
Go version: go1.21.8
Git commit: 8b79278
Built: Wed Mar 20 15:17:48 2024
OS/Arch: linux/amd64
Experimental: false
```
- **Display the docker installation details**
```bash
student@pod-sandy8-node01:~$ docker info
Client: Docker Engine - Community
Version: 26.0.0
Context: default
Debug Mode: false
Plugins:
buildx: Docker Buildx (Docker Inc.)
Version: v0.13.1
Path: /usr/libexec/docker/cli-plugins/docker-buildx
compose: Docker Compose (Docker Inc.)
Version: v2.25.0
Path: /usr/libexec/docker/cli-plugins/docker-compose
```
- **Add user into docker group**
```bash
groupadd docker
sudo usermod -aG docker $USER
sudo chmod 666 /var/run/docker.sock
```
- **Test the docker installation**
```bash
student@pod-sandy8-node01:~$ docker run registry.adinusa.id/btacademy/hello-world
Unable to find image 'registry.adinusa.id/btacademy/hello-world:latest' locally
latest: Pulling from btacademy/hello-world
2db29710123e: Pull complete
Digest: sha256:f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4
Status: Downloaded newer image for registry.adinusa.id/btacademy/hello-world:latest
```
- **Display the downloaded image**
```bash
student@pod-sandy8-node01:~$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 1403e55ab369 15 months ago 142MB
httpd latest 73c10eb9266e 15 months ago 145MB
registry.adinusa.id/btacademy/hello-world latest feb5d9fea6a5 2 years ago 13.3kB
```
- **Display all container (active or exit)**
```bash
student@pod-sandy8-node01:~$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
29966d10353a registry.adinusa.id/btacademy/hello-world "/hello" 20 minutes ago Exited (0) 20 minutes ago gifted_cannon
```
**2. Docker Run - part 1**
**Execute in node01**
- **Search image redis from dockerhub & harbor**
```bash
student@pod-sandy8-node01:~$ docker search redis
NAME DESCRIPTION STARS OFFICIAL
redis Redis is an open source key-value store that… 298 [OK]
redislabs/redisearch Redis With the RedisSearch module pre-loaded… 63
student@pod-sandy8-node01:~$ skopeo list-tags docker://registry.adinusa.id/btacademy/redis
{
"Repository": "registry.adinusa.id/btacademy/redis",
"Tags": [
"latest"
]
}
```
- **Running image redis**
```bash
docker run registry.adinusa.id/btacademy/redis # CTRL + c for quit
docker run -d registry.adinusa.id/btacademy/redis # Running in background (Background)
docker run -d --name redis1 registry.adinusa.id/btacademy/redis # Giving the container a name
```
- **Display running container**
```bash
student@pod-sandy8-node01:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5a6293c16eae registry.adinusa.id/btacademy/redis "docker-entrypoint.s…" 5 minutes ago Up 5 minutes 6379/tcp redis1
83c185992a9c registry.adinusa.id/btacademy/redis "docker-entrypoint.s…" 5 minutes ago Up 5 minutes 6379/tcp busy_jemison
student@pod-sandy8-node01:~$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5a6293c16eae registry.adinusa.id/btacademy/redis "docker-entrypoint.s…" 6 minutes ago Up 6 minutes 6379/tcp redis1
83c185992a9c registry.adinusa.id/btacademy/redis "docker-entrypoint.s…" 6 minutes ago Up 6 minutes 6379/tcp busy_jemison
```
- **Display all docker container**
```bash
student@pod-sandy8-node01:~$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5a6293c16eae registry.adinusa.id/btacademy/redis "docker-entrypoint.s…" 6 minutes ago Up 6 minutes 6379/tcp redis1
83c185992a9c registry.adinusa.id/btacademy/redis "docker-entrypoint.s…" 6 minutes ago Up 6 minutes 6379/tcp busy_jemison
2d41ea92d8cc registry.adinusa.id/btacademy/hello-world "/hello" 11 minutes ago Exited (0) 11 minutes ago youthful_stonebraker
```
- **Display container description**
```bash
student@pod-sandy8-node01:~$ docker inspect redis1
[
{
"Id": "5a6293c16eaeadb327c76bcfc84b7cd18d8d7abf7a01954dee68de533c96c1f0",
"Created": "2024-03-24T22:37:49.933988143Z",
"Path": "docker-entrypoint.sh",
"Args": [
"redis-server"
],
```
- **Display content of the logs in container**
```bash
student@pod-sandy8-node01:~$ docker logs redis1
1:C 24 Mar 2024 22:37:50.325 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 24 Mar 2024 22:37:50.326 # Redis version=7.0.11, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 24 Mar 2024 22:37:50.326 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
1:M 24 Mar 2024 22:37:50.327 * monotonic clock: POSIX clock_gettime
1:M 24 Mar 2024 22:37:50.328 * Running mode=standalone, port=6379.
1:M 24 Mar 2024 22:37:50.328 # Server initialized
```
- **Display live stream resource used in container**
```bash
student@pod-sandy8-node01:~$ docker stats redis1
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
5a6293c16eae redis1 0.22% 2.523MiB / 3.832GiB 0.06% 1.36kB / 1.01kB 0B / 0B 5
```
- **Display running process in container**
```bash
student@pod-sandy8-node01:~$ docker top redis1
UID PID PPID C STIME TTY TIME CMD
lxd 10103 10083 0 22:37 ? 00:00:01 redis-server *:6379
```
- **Shutdown the container**
```bash
student@pod-sandy8-node01:~$ docker stop redis1
redis1
```
**Execute in node02**
- **Search image nginx From DockerHub & Harbor**
```bash
student@pod-sandy8-node02:~$ docker search nginx
NAME DESCRIPTION STARS OFFICIAL
nginx Official build of Nginx. 52 [OK]
unit Official build of NGINX Unit: Universal Web … 25 [OK]
student@pod-sandy8-node02:~$ skopeo list-tags docker://registry.adinusa.id/btacademy/nginx
{
"Repository": "registry.adinusa.id/btacademy/nginx",
"Tags": [
"latest",
"mainline"
]
}
```
- **Running image nginx and expose to port host**
```bash
student@pod-sandy8-node02:~$ docker run -d --name nginx1 -p 80:80 registry.adinusa.id/btacademy/nginx:latest
Unable to find image 'registry.adinusa.id/btacademy/nginx:latest' locally
latest: Pulling from btacademy/nginx
26c5c85e47da: Pull complete
4f3256bdf66b: Pull complete
2019c71d5655: Pull complete
8c767bdbc9ae: Pull complete
```
- **Display a description of the nginx container**
```bash
student@pod-sandy8-node02:~$ docker inspect nginx1
[
{
"Id": "0d4c45460226666b5c534b1ccfd6c04d3baeb33cfa0902fcfd8f41c90680e419",
"Created": "2024-03-24T22:54:18.123243867Z",
"Path": "/docker-entrypoint.sh",
"Args": [
"nginx",
"-g",
"daemon off;"
],
```
- **Running image nginx and declare the container port**
```bash
student@pod-sandy8-node02:~$ docker run -d --name nginx2 -p 80 registry.adinusa.id/btacademy/nginx:latest
015cad8af11f8607bb392970847faf596f4a5daaadf5d4d9afcfd59a6729c7f0
```
- Test browsing
```bash
student@pod-sandy8-node02:~$ curl localhost:$(docker port nginx2 80 | cut -d : -f 2)
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
```
- **Display container (activate/exit)**
```bash
student@pod-sandy8-node02:~$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
015cad8af11f registry.adinusa.id/btacademy/nginx:latest "/docker-entrypoint.…" About a minute ago Up About a minute 0.0.0.0:32768->80/tcp, :::32768->80/tcp nginx2
0d4c45460226 registry.adinusa.id/btacademy/nginx:latest "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp nginx1
3126a1bcf6b5 registry.adinusa.id/btacademy/hello-world "/hello" 24 minutes ago Exited (0) 24 minutes ago heuristic_boyd
```
- **Display image docker**
```bash
student@pod-sandy8-node02:~$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.adinusa.id/btacademy/nginx latest 6efc10a0510f 11 months ago 142MB
nginx latest 1403e55ab369 15 months ago 142MB
httpd latest 73c10eb9266e 15 months ago 145MB
registry.adinusa.id/btacademy/hello-world latest feb5d9fea6a5 2 years ago 13.3kB
```
**3. Docker Run - part 2**
**Execute in node01**
- **Search image nginx from DockerHub & Harbor**
```bash
student@pod-sandy8-node01:~$ docker search nginx
NAME DESCRIPTION STARS OFFICIAL
nginx Official build of Nginx. 52 [OK]
unit Official build of NGINX Unit: Universal Web … 25 [OK]
student@pod-sandy8-node01:~$ skopeo list-tags docker://registry.adinusa.id/btacademy/nginx
{
"Repository": "registry.adinusa.id/btacademy/nginx",
"Tags": [
"latest",
"mainline"
]
}
```
- **Running an nginx image with the name nginx1 and expose port 8080**
```bash
student@pod-sandy8-node01:~$ docker run -d --name nginx1 -p 8080:80 registry.adinusa.id/btacademy/nginx:latest
Unable to find image 'registry.adinusa.id/btacademy/nginx:latest' locally
latest: Pulling from btacademy/nginx
26c5c85e47da: Already exists
4f3256bdf66b: Pull complete
2019c71d5655: Pull complete
8c767bdbc9ae: Pull complete
```
- **Displays a description of the nginx1 container**
```bash
student@pod-sandy8-node01:~$ docker inspect nginx1
[
{
"Id": "3cbe2dd92d82afb00103029d8c0251d56c3b8e12795196feae2c70710baedc92",
"Created": "2024-03-24T23:03:22.056021613Z",
"Path": "/docker-entrypoint.sh",
"Args": [
"nginx",
"-g",
"daemon off;"
],
```
- **Running an nginx image with the name nginx2 and expose port 8081**
```bash
student@pod-sandy8-node01:~$ docker run -d --name nginx2 -p 8081:80 registry.adinusa.id/btacademy/nginx:latest
4933a893274dc161cc25af4bd84b5557735518ab7b58761d53fb4f99e75f3831
```
- **Display container (activate/exit)**
```bash
student@pod-sandy8-node01:~$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4933a893274d registry.adinusa.id/btacademy/nginx:latest "/docker-entrypoint.…" About a minute ago Up About a minute 0.0.0.0:8081->80/tcp, :::8081->80/tcp nginx2
3cbe2dd92d82 registry.adinusa.id/btacademy/nginx:latest "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp, :::8080->80/tcp nginx1
5a6293c16eae registry.adinusa.id/btacademy/redis "docker-entrypoint.s…" 28 minutes ago Exited (0) 14 minutes ago redis1
83c185992a9c registry.adinusa.id/btacademy/redis "docker-entrypoint.s…" 28 minutes ago Up 28 minutes 6379/tcp busy_jemison
student@pod-sandy8-node01:~$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4933a893274d registry.adinusa.id/btacademy/nginx:latest "/docker-entrypoint.…" About a minute ago Up About a minute 0.0.0.0:8081->80/tcp, :::8081->80/tcp nginx2
3cbe2dd92d82 registry.adinusa.id/btacademy/nginx:latest "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp, :::8080->80/tcp nginx1
5a6293c16eae registry.adinusa.id/btacademy/redis "docker-entrypoint.s…" 28 minutes ago Exited (0) 14 minutes ago redis1
83c185992a9c registry.adinusa.id/btacademy/redis "docker-entrypoint.s…" 28 minutes ago Up 28 minutes 6379/tcp busy_jemison
```
- **Check nginx output on containers**
```bash
student@pod-sandy8-node01:~$ curl localhost:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
student@pod-sandy8-node01:~$ curl localhost:8081
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
```
- **Accessing the container**
```bash
student@pod-sandy8-node01:~$ docker exec -it nginx2 /bin/bash
root@4933a893274d:/#
```
- **Update and install editor on the container**
```bash
root@4933a893274d:/# apt-get update -y && apt-get install nano -y
Get:1 http://deb.debian.org/debian bullseye InRelease [116 kB]
Get:2 http://deb.debian.org/debian-security bullseye-security InRelease [48.4 kB]
Get:3 http://deb.debian.org/debian bullseye-updates InRelease [44.1 kB]
```
- **Edit index.html and move index.html to default directory nginx**

```bash
root@4933a893274d:/# mv index.html /usr/share/nginx/html
```
- **Restart service nginx**
```bash
root@4933a893274d:/# service nginx restart
Restarting nginx: nginx
student@pod-sandy8-node01:~$
```
- **Rerun the container**
```bash
student@pod-sandy8-node01:~$ docker start nginx2
nginx2
```
- **Display container**
```bash
student@pod-sandy8-node01:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4933a893274d registry.adinusa.id/btacademy/nginx:latest "/docker-entrypoint.…" 17 minutes ago Up 10 minutes 0.0.0.0:8081->80/tcp, :::8081->80/tcp nginx2
3cbe2dd92d82 registry.adinusa.id/btacademy/nginx:latest "/docker-entrypoint.…" 19 minutes ago Up 19 minutes 0.0.0.0:8080->80/tcp, :::8080->80/tcp nginx1
83c185992a9c registry.adinusa.id/btacademy/redis "docker-entrypoint.s…" 45 minutes ago Up 45 minutes 6379/tcp busy_jemison
```
- **Check nginx output on containers**
```bash
student@pod-sandy8-node01:~$ curl localhost:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
student@pod-sandy8-node01:~$ curl localhost:8081
hello, sandy8.
```
- **Display a description of the container**
```bash
student@pod-sandy8-node01:~$ docker inspect nginx1
[
{
"Id": "3cbe2dd92d82afb00103029d8c0251d56c3b8e12795196feae2c70710baedc92",
"Created": "2024-03-24T23:03:22.056021613Z",
"Path": "/docker-entrypoint.sh",
"Args": [
"nginx",
"-g",
"daemon off;"
],
student@pod-sandy8-node01:~$ docker inspect nginx2
[
{
"Id": "4933a893274dc161cc25af4bd84b5557735518ab7b58761d53fb4f99e75f3831",
"Created": "2024-03-24T23:04:48.222606361Z",
"Path": "/docker-entrypoint.sh",
"Args": [
"nginx",
"-g",
"daemon off;"
],
```
- **Display the log content in the container**
```bash
student@pod-sandy8-node01:~$ docker logs nginx1
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2024/03/24 23:03:22 [notice] 1#1: using the "epoll" event method
```
- **Displays the live resources used in the container**
```bash
student@pod-sandy8-node01:~$ docker stats nginx1
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
3cbe2dd92d82 nginx1 0.00% 4.094MiB / 3.832GiB 0.10% 4.39kB / 3.58kB 0B / 12.3kB 5
student@pod-sandy8-node01:~$ docker stats nginx2
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
4933a893274d nginx2 0.00% 3.914MiB / 3.832GiB 0.10% 1.71kB / 1.68kB 0B / 4.1kB 5
```
- **Display running process in container**
```bash
student@pod-sandy8-node01:~$ docker top nginx1
UID PID PPID C STIME TTY TIME CMD
root 10470 10451 0 23:03 ? 00:00:00 nginx: master process nginx -g daemon off;
systemd+ 10509 10470 0 23:03 ? 00:00:00 nginx: worker process
systemd+ 10510 10470 0 23:03 ? 00:00:00 nginx: worker process
student@pod-sandy8-node01:~$ docker top nginx2
UID PID PPID C STIME TTY TIME CMD
root 11142 11121 0 23:11 ? 00:00:00 nginx: master process nginx -g daemon off;
systemd+ 11170 11142 0 23:11 ? 00:00:00 nginx: worker process
systemd+ 11171 11142 0 23:11 ? 00:00:00 nginx: worker process
```
**Docker run practice**
- **Search image ubuntu from DockerHub & Harbor**
```bash
student@pod-sandy8-node01:~$ docker search ubuntu
NAME DESCRIPTION STARS OFFICIAL
ubuntu Ubuntu is a Debian-based Linux operating sys… 16965 [OK]
websphere-liberty WebSphere Liberty multi-architecture images … 298 [OK]
student@pod-sandy8-node01:~$ skopeo list-tags docker://registry.adinusa.id/btacademy/ubuntu
{
"Repository": "registry.adinusa.id/btacademy/ubuntu",
"Tags": [
"16.04",
"18.04",
"20.04",
"20.10",
"22.04",
"latest"
]
}
```
- **Pull image ubuntu from harbor**
```bash
student@pod-sandy8-node01:~$ docker pull registry.adinusa.id/btacademy/ubuntu
Using default tag: latest
latest: Pulling from btacademy/ubuntu
74ac377868f8: Pull complete
Digest: sha256:ebc06404a3af2fe5b4e97f34b308bc4810e8a44cb6e59109eec81e7779b0c4b1
Status: Downloaded newer image for registry.adinusa.id/btacademy/ubuntu:latest
registry.adinusa.id/btacademy/ubuntu:latest
```
- **Running the ubuntu container and access to the console**
```bash
student@pod-sandy8-node01:~$ docker run -it --name ubuntu1 registry.adinusa.id/btacademy/ubuntu
root@618ae9edaa74:/#
root@618ae9edaa74:/# exit
exit
student@pod-sandy8-node01:~$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
618ae9edaa74 registry.adinusa.id/btacademy/ubuntu "/bin/bash" About a minute ago Exited (0) 25 seconds ago ubuntu1
4933a893274d registry.adinusa.id/btacademy/nginx:latest "/docker-entrypoint.…" 29 minutes ago Up 22 minutes 0.0.0.0:8081->80/tcp, :::8081->80/tcp nginx2
3cbe2dd92d82 registry.adinusa.id/btacademy/nginx:latest "/docker-entrypoint.…" 30 minutes ago Up 30 minutes 0.0.0.0:8080->80/tcp, :::8080->80/tcp nginx1
5a6293c16eae registry.adinusa.id/btacademy/redis "docker-entrypoint.s…" 56 minutes ago Exited (0) 43 minutes ago redis1
```
- **Run the ubuntu container and delete it when exiting the container**
```bash
student@pod-sandy8-node01:~$ docker run -it --rm --name ubuntu2 registry.adinusa.id/btacademy/ubuntu
root@df50ac710cd1:/# exit
exit
student@pod-sandy8-node01:~$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
618ae9edaa74 registry.adinusa.id/btacademy/ubuntu "/bin/bash" 2 minutes ago Exited (0) About a minute ago ubuntu1
4933a893274d registry.adinusa.id/btacademy/nginx:latest "/docker-entrypoint.…" 30 minutes ago Up 24 minutes 0.0.0.0:8081->80/tcp, :::8081->80/tcp nginx2
3cbe2dd92d82 registry.adinusa.id/btacademy/nginx:latest "/docker-entrypoint.…" 32 minutes ago Up 32 minutes 0.0.0.0:8080->80/tcp, :::8080->80/tcp nginx1
5a6293c16eae registry.adinusa.id/btacademy/redis "docker-entrypoint.s…" 57 minutes ago Exited (0) 44 minutes ago redis1
```
**3. Docker Run - part 3**
**Execute in node01**
- **Running mysql container with additional parameters**
```bash
student@pod-sandy8-node01:~$ docker run -d --name my-mysql -e MYSQL_ROOT_PASSWORD=RAHASIA -e MYSQL_DATABASE=latihan05 -p 3306:3306 registry.adinusa.id/btacademy/mysql
Unable to find image 'registry.adinusa.id/btacademy/mysql:latest' locally
latest: Pulling from btacademy/mysql
328ba678bf27: Pull complete
f3f5ff008d73: Pull complete
dd7054d6d0c7: Pull complete
70b5d4e8750e: Pull complete
cdc4a7b43bdd: Pull complete
```
- **Pull image phpmyadmin from harbor**
```bash
student@pod-sandy8-node01:~$ docker pull registry.adinusa.id/btacademy/phpmyadmin:latest
latest: Pulling from btacademy/phpmyadmin
26c5c85e47da: Already exists
39c8021d1258: Pull complete
dff43c2de684: Downloading [======> ] 11.89MB/91.64MB
383987c505e8: Download complete
3fd742e8a904: Downloading [===========================> ] 10.62MB/19.25MB
ccf9807e8362: Download complete
11cc7ce10028: Download complete
```
- **Running phpmyadmin container and connect it with mysql container**
```bash
student@pod-sandy8-node01:~$ docker run --name my-phpmyadmin -d --link my-mysql:db -p 8090:80 registry.adinusa.id/btacademy/phpmyadmin
102dab1f0134ffd98dd954ab3c2d590fd5ee398a567436d9b495565753e9dd39
```
- **Test browsing**
open in browser http://10.10.10.11:8090 login with user: root dan password: RAHASIA

**Docker run practice**
- **Run ubuntu containers with names ubuntu1 & ubuntu2**
```bash
student@pod-sandy8-node01:~$ docker rm ubuntu1
student@pod-sandy8-node01:~$ docker run -dit --name ubuntu1 registry.adinusa.id/btacademy/ubuntu
7ad2180269ec88c19b99aa9efb5d2390fb0d2d7ef91830192527d5ab7725f28a
student@pod-sandy8-node01:~$ docker run -dit --name ubuntu2 registry.adinusa.id/btacademy/ubuntu
dbb9ff85d0c4ddbf83f57a07048689a0978b1d9e64f8a704877de4b9d087a386
```
- **Display list container**
```bash
student@pod-sandy8-node01:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dbb9ff85d0c4 registry.adinusa.id/btacademy/ubuntu "/bin/bash" 57 seconds ago Up 56 seconds ubuntu2
7ad2180269ec registry.adinusa.id/btacademy/ubuntu "/bin/bash" About a minute ago Up About a minute ubuntu1
102dab1f0134 registry.adinusa.id/btacademy/phpmyadmin "/docker-entrypoint.…" 4 minutes ago Up 4 minutes 0.0.0.0:8090->80/tcp, :::8090->80/tcp my-phpmyadmin
b908f7583653 registry.adinusa.id/btacademy/mysql "docker-entrypoint.s…" 8 minutes ago Up 8 minutes 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp my-mysql
```
- **Pause container ubuntu**
```bash
student@pod-sandy8-node01:~$ docker pause ubuntu1
ubuntu1
student@pod-sandy8-node01:~$ docker pause ubuntu2
ubuntu2
```
- **Check in list container if the container status is paused**
```bash
student@pod-sandy8-node01:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dbb9ff85d0c4 registry.adinusa.id/btacademy/ubuntu "/bin/bash" 2 minutes ago Up 2 minutes (Paused) ubuntu2
7ad2180269ec registry.adinusa.id/btacademy/ubuntu "/bin/bash" 2 minutes ago Up 2 minutes (Paused) ubuntu1
102dab1f0134 registry.adinusa.id/btacademy/phpmyadmin "/docker-entrypoint.…" 6 minutes ago Up 6 minutes 0.0.0.0:8090->80/tcp, :::8090->80/tcp my-phpmyadmin
b908f7583653 registry.adinusa.id/btacademy/mysql "docker-entrypoint.s…" 9 minutes ago Up 9 minutes 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp my-mysql
```
- **Check resource usage when the ubuntu container is paused**
```bash
student@pod-sandy8-node01:~$ docker stats ubuntu1
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
7ad2180269ec ubuntu1 0.00% 848KiB / 3.832GiB 0.02% 1.87kB / 866B 0B / 0B 1
student@pod-sandy8-node01:~$ docker stats ubuntu2
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
dbb9ff85d0c4 ubuntu2 0.00% 836KiB / 3.832GiB 0.02% 1.29kB / 866B 0B / 0B 1
```
- **Unpause container ubuntu1**
```bash
student@pod-sandy8-node01:~$ docker unpause ubuntu1
ubuntu1
```
**Docker run practice**
- **Create database containers with limited specifications**
```bash
student@pod-sandy8-node01:~$ docker container run -d --name ch6_mariadb --memory 256m --cpu-shares 1024 --cap-drop net_raw -e MYSQL_ROOT_PASSWORD=test registry.adinusa.id/btacademy/mariadb:5.5
Unable to find image 'registry.adinusa.id/btacademy/mariadb:5.5' locally
5.5: Pulling from btacademy/mariadb
a7344f52cb74: Downloading [=======> ] 9.731MB/67.19MB
515c9bb51536: Download complete
e1eabe0537eb: Download complete
4701f1215c13: Download complete
1f47c10fd782: Download complete
```
- **Create a wordpress container and connect it to the database container**
```bash
student@pod-sandy8-node01:~$ docker container run -d -p 80:80 -P --name ch6_wordpress --memory 512m --cpu-shares 512 \
> --cap-drop net_raw --link ch6_mariadb:mysql -e WORDPRESS_DB_PASSWORD=test \
> registry.adinusa.id/btacademy/wordpress:5.0.0-php7.2-apache
Unable to find image 'registry.adinusa.id/btacademy/wordpress:5.0.0-php7.2-apache' locally
5.0.0-php7.2-apache: Pulling from btacademy/wordpress
a5a6f2f73cd8: Downloading [=================> ] 8.027MB/22.49MB
633e0d1cd2a3: Download complete
fcdfdf7118ba: Downloading [=====> ] 7.569MB/67.43MB
4e7dc76b1769: Download complete
```
- **Check logs, running process, and resource**
```bash
student@pod-sandy8-node01:~$ docker logs ch6_mariadb
Initializing database
240324 23:56:47 [Note] /usr/sbin/mysqld (mysqld 5.5.64-MariaDB-1~trusty) starting as process 73 ...
240324 23:56:48 [Note] /usr/sbin/mysqld (mysqld 5.5.64-MariaDB-1~trusty) starting as process 80 ...
PLEASE REMEMBER TO SET A PASSWORD FOR THE MariaDB root USER !
To do so, start the server, then issue the following commands:
'/usr/bin/mysqladmin' -u root password 'new-password'
'/usr/bin/mysqladmin' -u root -h password 'new-password'
Alternatively you can run:
'/usr/bin/mysql_secure_installation'
which will also give you the option of removing the test
databases and anonymous user created by default. This is
strongly recommended for production servers.
See the MariaDB Knowledgebase at http://mariadb.com/kb or the
MySQL manual for more instructions.
student@pod-sandy8-node01:~$ docker logs ch6_wordpress
WordPress not found in /var/www/html - copying now...
Complete! WordPress has been successfully copied to /var/www/html
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.10. Set the 'ServerName' directive globally to suppress this message
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.10. Set the 'ServerName' directive globally to suppress this message
[Mon Mar 25 00:00:01.114803 2024] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.25 (Debian) PHP/7.2.13 configured -- resuming normal operations
[Mon Mar 25 00:00:01.114928 2024] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'
student@pod-sandy8-node01:~$ docker top ch6_mariadb
UID PID PPID C STIME TTY TIME CMD
lxd 12527 12504 0 Mar24 ? 00:00:00 mysqld
student@pod-sandy8-node01:~$ docker top ch6_wordpress
UID PID PPID C STIME TTY TIME CMD
root 12871 12847 0 Mar24 ? 00:00:00 apache2 -DFOREGROUND
www-data 13090 12871 0 00:00 ? 00:00:00 apache2 -DFOREGROUND
www-data 13091 12871 0 00:00 ? 00:00:00 apache2 -DFOREGROUND
www-data 13092 12871 0 00:00 ? 00:00:00 apache2 -DFOREGROUND
student@pod-sandy8-node01:~$ docker stats ch6_mariadb
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
a0a6e14a010f ch6_mariadb 0.13% 82.8MiB / 256MiB 32.34% 2.83kB / 1.67kB 4.6MB / 49MB 20
student@pod-sandy8-node01:~$ docker stats ch6_wordpress
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
e33b8f77419c ch6_wordpress 0.01% 21.12MiB / 512MiB 4.13% 1.67kB / 1.75kB 0B / 42.6MB 6
```
- **Test browsing**
Access to http//10.10.10.11/

**Tittle 3: Managing Docker Container**
-
**1. Managing the Life Cycle of Containers - 1**
Docker has a number of commands that can be used to create and manage containers. The following is a summary of the most frequently used commands to change container state.

Apart from that, Docker also provides a number of commands to get information about running and stopped containers. The following is a summary of the most frequently used commands to retrieve information regarding Docker containers.

**2. Managing the Life Cycle of Containers - 2**
- **Managing Containers**
Docker provides the following commands for managing containers:
**docker ps** : This command is responsible for displaying the list of running containers.
**CONTAINER ID** : Each container, when created, gets a container ID, which is a hexadecimal number and looks like an image ID, but is actually unrelated.
**IMAGE** : The container image used to start the container.
**COMMAND** : Commands that are executed when the container starts.
**CREATED** : The date and time the container was started.
**STATUS** : The total time the container was running, if it is still running, or the time since it was closed.
**PORT** : The port exposed by the container or port forwarding, if configured.
**NAME** : Container name.
- **Docker Network**
One of the reasons for the power of Docker containers and services is their ability to interconnect or interface with non-Docker workloads. Docker containers and services don't need to know that they run on Docker or whether their counterparts also use Docker. Whether your Docker host runs on Linux, Windows, or both, you can manage it platform-agnostically with Docker.
In this discussion, we will define some basic concepts about Docker networking to prepare you to design and deploy applications to take full advantage of these capabilities.
**bridge** : The default network driver.
**host** : Remove network isolation between the container and the Docker host.
**overlay** : Overlay networks connect multiple Docker daemons together.
**ipvlan** : IPvlan networks provide full control over both IPv4 and IPv6 addressing.
**macvlan** : Assign a MAC address to a container.
**none** : Completely isolate a container from the host and other containers.
- **Docker Network Plugin**
You can also use third-party networking plugins with Docker. This plugin can be downloaded from Docker Hub or other vendors.
**3. Mount Volume - part 1**
**Execute in node01**
- **Create working directory**
```bash
student@pod-sandy8-node01:~$ cd $HOME
student@pod-sandy8-node01:~$ mkdir -p latihan/latihan01-volume
student@pod-sandy8-node01:~$ cd latihan/latihan01-volume
student@pod-sandy8-node01:~/latihan/latihan01-volume$
```
- **Create file and container for data volume with name my-volume**
```bash
student@pod-sandy8-node01:~/latihan/latihan01-volume$ for i in {1..10};do touch file-$i;done
student@pod-sandy8-node01:~/latihan/latihan01-volume$ sudo docker create -v /my-volume --name my-volume registry.adinusa.id/btacademy/busybox
Unable to find image 'registry.adinusa.id/btacademy/busybox:latest' locally
latest: Pulling from btacademy/busybox
4b35f584bb4f: Pull complete
Digest: sha256:acaddd9ed544f7baf3373064064a51250b14cfe3ec604d65765a53da5958e5f5
Status: Downloaded newer image for registry.adinusa.id/btacademy/busybox:latest
6e27dc0e3407bca8e82b528b6c7c413ce9511c8b15c216476ba6243b004e35e7
student@pod-sandy8-node01:~/latihan/latihan01-volume$ sudo docker cp . my-volume:/my-volume
Successfully copied 6.66kB to my-volume:/my-volume
```
- **Mount the volume into the container**
```bash
student@pod-sandy8-node01:~/latihan/latihan01-volume$ docker run --volumes-from my-volume registry.adinusa.id/btacademy/ubuntu ls /my-volume
file-1
file-10
file-2
file-3
file-4
file-5
file-6
file-7
file-8
file-9
```
**4. Mount Volume with NFS Server**
**Execute in node01**
- **Create working directory**
```bash
student@pod-sandy8-node01:~$ sudo mkdir -p /data/nfs-storage01/
```
- **Create the NFS Server with docker**
```bash
student@pod-sandy8-node01:~$ docker run -itd --privileged --restart unless-stopped -e SHARED_DIRECTORY=/data -v /data/nfs-storage01:/data -p 2049:2049 registry.adinusa.id/btacademy/nfs-server-alpine:12
Unable to find image 'registry.adinusa.id/btacademy/nfs-server-alpine:12' locally
12: Pulling from btacademy/nfs-server-alpine
bdf0201b3a05: Pull complete
8e751f03d47e: Pull complete
68ecfeaf6b18: Extracting [=================================================> ] 4.981MB/5.022MB
```
**Execute in node02**
- **Install the necessary packages, mount the volume on the NFS client and then create a file to check out the volume**
```bash
student@pod-sandy8-node02:~$ ssh 10.7.7.20
Warning: Permanently added '10.7.7.20' (ED25519) to the list of known hosts.
Welcome to Ubuntu 22.04.1 LTS (GNU/Linux 5.15.0-46-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Mon Mar 25 13:01:33 UTC 2024
System load: 0.0 Users logged in: 1
Usage of /: 18.3% of 17.87GB IPv4 address for docker0: 172.17.0.1
Memory usage: 8% IPv4 address for ens33: 192.168.22.12
Swap usage: 0% IPv4 address for ens34: 10.10.10.12
Processes: 222 IPv4 address for ens35: 10.7.7.20
```
```bash
student@pod-sandy8-node02:~$ sudo apt install nfs-client -y
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Note, selecting 'nfs-common' instead of 'nfs-client'
The following additional packages will be installed:
keyutils libnfsidmap1 rpcbind
Suggested packages:
watchdog
The following NEW packages will be installed:
keyutils libnfsidmap1 nfs-common rpcbind
```
```bash
student@pod-sandy8-node02:~$ sudo mount -v -t nfs4 10.7.7.10:/ /mnt
mount.nfs4: timeout set for Mon Mar 25 13:10:45 2024
mount.nfs4: trying text-based options 'vers=4.2,addr=10.7.7.10,clientaddr=10.7.7.20'
student@pod-sandy8-node02:~$ df -h
Filesystem Size Used Avail Use% Mounted on
tmpfs 393M 1.3M 392M 1% /run
/dev/sda1 18G 3.3G 15G 19% /
tmpfs 2.0G 0 2.0G 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
/dev/sda15 105M 5.3M 100M 5% /boot/efi
tmpfs 393M 4.0K 393M 1% /run/user/1000
10.7.7.10:/ 18G 5.7G 13G 32% /mnt
```
```bash
student@pod-sandy8-node02:~$ sudo touch /mnt/file1.txt
student@pod-sandy8-node02:~$ sudo touch /mnt/file2.txt
```
**Execute in node01**
- **Verification**
```bash
student@pod-sandy8-node01:~$ ls /data/nfs-storage01/
file1.txt file2.txt
```
**5. Mount Volume with Read-only Mode**
**Execute in node01**
- **Create docker volume**
```bash
student@pod-sandy8-node01:~$ docker volume create my-vol
my-vol
```
- **Display list docker volume**
```bash
student@pod-sandy8-node01:~$ docker volume ls
DRIVER VOLUME NAME
local 3bc31f280461ce4ade414ee60dbc950bd38843d183544fb460c8107e84ebe486
local 4e80ae9008cf859ae480cb78444994810b9d2d6a40f6f16af6bca363a351d0dd
local my-vol
```
- **Display docker volume details**
```bash
student@pod-sandy8-node01:~$ docker volume inspect my-vol
[
{
"CreatedAt": "2024-03-25T13:14:22Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-vol",
"Options": null,
"Scope": "local"
}
]
```
- **Running the container with volume read and write access**
```bash
student@pod-sandy8-node01:~$ docker run -d --name=nginx-rwvol -v my-vol:/usr/share/nginx/html -p 4005:80 registry.adinusa.id/btacademy/nginx:latest
719b535e9523ebb4a620d51c29628d1a48a620c28c129860a4186ed6eea13e1c
```
- **Display the IP Address of the container**
```bash
student@pod-sandy8-node01:~$ docker inspect nginx-rwvol | jq -r '.[].NetworkSettings.IPAddress'
172.17.0.3
```
- **Test browsing to IP Address of the container**
```bash
student@pod-sandy8-node01:~$ curl 172.17.0.3
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
```
- **Create index.html file and move it to the source volume directory**
```bash
student@pod-sandy8-node01:~$ docker run -d --name=nginx-rovol -v my-vol:/usr/share/nginx/html:ro registry.adinusa.id/btacademy/nginx:latest
57b3cb68e9d7802baa501d16f23f5d376fe2193ec1ef290fb8b4bdbe9d173968
```
- **View the nginx-rovol container details and pay attention to the Mode in Mounts section**
```bash
student@pod-sandy8-node01:~$ docker inspect nginx-rovol | jq '.[].Mounts'
[
{
"Type": "volume",
"Name": "my-vol",
"Source": "/var/lib/docker/volumes/my-vol/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "ro",
"RW": false,
"Propagation": ""
}
]
```
**6. Volume Driver**
**Execute in node02**
- **Create directory /share and Create index.html**
```bash
student@pod-sandy8-node02:~$ sudo mkdir /share
student@pod-sandy8-node02:~$ sudo chmod 777 /share
student@pod-sandy8-node02:~$ echo "Hello Adinusa!" > /share/index.html
```
**Execute in node01**
- **Instal plugin sshfs and set plugin sshfs**
```bash
student@pod-sandy8-node01:~$ docker plugin install --grant-all-permissions vieux/sshfs
latest: Pulling from vieux/sshfs
Digest: sha256:1d3c3e42c12138da5ef7873b97f7f32cf99fb6edde75fa4f0bcf9ed277855811
52d435ada6a4: Complete
Installed plugin vieux/sshfs
student@pod-sandy8-node01:~$ docker plugin ls
ID NAME DESCRIPTION ENABLED
4eb5df45fc0b vieux/sshfs:latest sshFS plugin for Docker true
student@pod-sandy8-node01:~$ docker plugin disable 4eb5df45fc0b
4eb5df45fc0b
student@pod-sandy8-node01:~$ docker plugin set vieux/sshfs sshkey.source=/home/student/.ssh/
student@pod-sandy8-node01:~$ docker plugin enable 4eb5df45fc0b
4eb5df45fc0b
student@pod-sandy8-node01:~$ docker plugin ls
ID NAME DESCRIPTION ENABLED
4eb5df45fc0b vieux/sshfs:latest sshFS plugin for Docker true
```
- **Creating docker volume with driver sshfs**
```bash
student@pod-sandy8-node01:~$ docker volume create --driver vieux/sshfs -o sshcmd=student@10.7.7.20:/share -o allow_other sshvolume
sshvolume
```
- **Test running container with the volume**
```bash
student@pod-sandy8-node01:~$ docker run -d --name=nginxtest-sshfs -p 8090:80 -v sshvolume:/usr/share/nginx/html registry.adinusa.id/btacademy/nginx:latest
e53b51ad7f50ae48532614af3fd0a50b67f23ab2884732d2903cbab1b1ff9ef4
```
- **Test browsing**
```bash
student@pod-sandy8-node01:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e53b51ad7f50 registry.adinusa.id/btacademy/nginx:latest "/docker-entrypoint.…" 47 seconds ago Up 45 seconds 0.0.0.0:8090->80/tcp, :::8090->80/tcp nginxtest-sshfs
student@pod-sandy8-node01:~$ curl http://localhost:8090
Hello Adinusa!
```
**7. Default Bridge Network**
**Execute in node01**
- **Display a list of networks on the current docker network**
```bash
student@pod-sandy8-node01:~$ sudo docker network ls
NETWORK ID NAME DRIVER SCOPE
34fcfe1fcfbc bridge bridge local
ac3acf6f40a0 host host local
3116eb5918d0 none null local
```
- **Run 2 alpine container running ash shell**
```bash
student@pod-sandy8-node01:~$ docker run -dit --name alpine1 registry.adinusa.id/btacademy/alpine ash
Unable to find image 'registry.adinusa.id/btacademy/alpine:latest' locally
latest: Pulling from btacademy/alpine
f56be85fc22e: Pull complete
Digest: sha256:b6ca290b6b4cdcca5b3db3ffa338ee0285c11744b4a6abaa9627746ee3291d8d
Status: Downloaded newer image for registry.adinusa.id/btacademy/alpine:latest
c6abede0026d33a89f9f287f97641db07e0ff73d1bf624bf26dd43c23cf4613c
student@pod-sandy8-node01:~$ docker run -dit --name alpine2 registry.adinusa.id/btacademy/alpine ash
1ff4e262cc9bab08de7d500780524f0414f6d980dbe624df06a3e7f5bea324c8
student@pod-sandy8-node01:~$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1ff4e262cc9b registry.adinusa.id/btacademy/alpine "ash" 9 seconds ago Up 8 seconds alpine2
c6abede0026d registry.adinusa.id/btacademy/alpine "ash" 14 seconds ago Up 14 seconds alpine1
```
- **Create a new docker network and attach it to the alpine1 container**
```bash
student@pod-sandy8-node01:~$ docker network create --driver bridge bridge1
ed7dfb02bacdc00a1649baf6059adbb8fd1ec1233762602b33eaae1efdf87815
student@pod-sandy8-node01:~$ docker network connect bridge1 alpine1
```
- **Check the IP address of the alpine2 container**
```bash
student@pod-sandy8-node01:~$ docker inspect alpine2 | jq -r '.[].NetworkSettings.IPAddress'
172.17.0.7
```
- **Access to alpine1 container**
```bash
student@pod-sandy8-node01:~$ docker exec -it alpine1 sh
/ #
```
- **Display the IP address of container alpine1**
```bash
/ # ip add
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
16: eth0@if17: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:06 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.6/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:6/64 scope link
valid_lft forever preferred_lft forever
21: eth1@if22: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.2/16 brd 172.18.255.255 scope global eth1
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe12:2/64 scope link
valid_lft forever preferred_lft forever
```
- **Ping test to the internet on container alpine1 (Success)**
```bash
/ # ping -c 3 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=127 time=228.150 ms
64 bytes from 8.8.8.8: seq=1 ttl=127 time=30.347 ms
64 bytes from 8.8.8.8: seq=2 ttl=127 time=24.894 ms
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 24.894/94.463/228.150 ms
```
- **Ping test to IP Address of alpine2 container (Success)**
```bash
/ # ping -c 3 172.17.0.7
PING 172.17.0.7 (172.17.0.7): 56 data bytes
64 bytes from 172.17.0.7: seq=0 ttl=64 time=0.303 ms
64 bytes from 172.17.0.7: seq=1 ttl=64 time=0.415 ms
64 bytes from 172.17.0.7: seq=2 ttl=64 time=0.157 ms
--- 172.17.0.7 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.157/0.291/0.415 ms
```
- **Ping test to name of alpine2 container (failed)**
```bash
/ # ping -c 3 alpine2
ping: bad address 'alpine2'
```
**8. Host Network**
**Execute in node01**
- **Run the container from the nginx image with the network host**
```bash
student@pod-sandy8-node01:~$ docker run -itd --network host --name my_nginx registry.adinusa.id/btacademy/nginx
2ce71535f812fd1baa244d40b145a15a1e8636826750979966b2e12e674e1fb0
```
- **Test browsing to localhost**
```bash
student@pod-sandy8-node01:~$ curl http://localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
```
- **Verification IP Address and bound port 80**
```bash
student@pod-sandy8-node01:~$ ip add
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:16:79:a9 brd ff:ff:ff:ff:ff:ff
altname enp2s1
inet 192.168.22.11/24 brd 192.168.22.255 scope global ens33
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe16:79a9/64 scope link
valid_lft forever preferred_lft forever
3: ens34: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:16:79:b3 brd ff:ff:ff:ff:ff:ff
altname enp2s2
inet 10.10.10.11/24 brd 10.10.10.255 scope global ens34
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe16:79b3/64 scope link
valid_lft forever preferred_lft forever
4: ens35: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:16:79:bd brd ff:ff:ff:ff:ff:ff
altname enp2s3
inet 10.7.7.10/24 brd 10.7.7.255 scope global ens35
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe16:79bd/64 scope link
valid_lft forever preferred_lft forever
5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:2c:b3:7d:d0 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:2cff:feb3:7dd0/64 scope link
valid_lft forever preferred_lft forever
student@pod-sandy8-node01:~$ sudo netstat -tulpn | grep :80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 8528/nginx: master
tcp 0 0 0.0.0.0:8090 0.0.0.0:* LISTEN 6297/docker-proxy
tcp6 0 0 :::80 :::* LISTEN 8528/nginx: master
tcp6 0 0 :::8090 :::* LISTEN 6303/docker-proxy
```
**Tittle 4: Creating Custom Docker Container Image**
-
**Docker images**
What is Docker Images?
Docker images are like "templates" used to create containers. On a Linux system, everything is considered a file, including the operating system itself. So, a Docker image is basically like a big “package” that contains everything needed to run an application in a container. It's like having a large "archive" containing all the necessary components, such as files and folders, that "stack" on top of each other to form a complete picture.
**The layered filesystem**
The layered file system in a container image is like having several "layers" that are "stacked" on top of each other. Docker images, which are templates for containers, consist of several interrelated layers. The first layer, also called the base layer, is the basis of the image. This is similar to putting together several "puzzles" that make up the overall picture.

Image as a stack of layers Each individual layer contains files and folders. Each layer only contains changes to the file system of the underlying layer. A storage driver handles the details regarding how these layers interact with each other. Various storage drivers are available that have advantages and disadvantages in different situations.
The layers of a container image are all immutable. Immutable means that once created, the layer can never be changed. The only operation that affects layers is their physical deletion. The stiffness of these layers is important because it opens up many opportunities, as we will see.
In the following image, we can see how a custom image for a web application, using Nginx as the web server, could look.

An example of an Alpine and Nginx based custom image
Our base layer here consists of the Alpine Linux distribution. Then, on top of that, we have the Add Nginx layer where Nginx is added on top of Alpine. Finally, the third layer contains all the files that make up the web application, such as HTML, CSS, and JavaScript files.
As mentioned before, each image starts with a base image. Typically, this base image is one of the official images found on Docker Hub, such as a Linux, Alpine, Ubuntu, or CentOS distro. However, it is also possible to create images from scratch.
**Docker Registry**
An overview of Docker Registry
In this section, we will discuss Docker Registry. Docker Registry is an application that you can run anywhere and is used to store your Docker images. We'll compare Docker Registry and Docker Hub, and discuss how to choose between the two. At the end of this section, you'll learn how to run Docker Registry yourself and determine if it's right for you.

Docker Registry is an open source application that you can use to store Docker images on the platform of your choice. This allows you to keep the images private or share them as needed.
Docker Registry is suitable for use if you want to have your own registry without having to pay for Docker Hub's private features. Now, let's compare Docker Hub and Docker Registry to help you choose the appropriate platform for storing your images.
Docker Registry Features:
- You can manage your own registry from where you can present all repositories as private, public, or a mix of both.
- You can scale the registry as needed, based on the number of images you host or the number of pull requests you serve.
- Everything can be run via the command line.
Docker Hub provides:
- Easy to use GUI based interface to manage your images.
- A place in the cloud that is set up to handle public and/or private images.
- You don't need to bother managing the server that hosts all your images.
**Docker Hub**
Docker Hub is the easiest way to build, manage, and deliver your team's container applications.
The Docker Hub repository lets you share container images with your team, customers, or the Docker community at large.
**1. Exploring Dockerfile**
**Execute in node01**
- **Clone repository for training**
```bash
student@pod-sandy8-node01:~$ git clone https://github.com/spkane/docker-node-hello.git \
> --config core.autocrlf=input latihan01
Cloning into 'latihan01'...
remote: Enumerating objects: 60, done.
remote: Counting objects: 100% (13/13), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 60 (delta 6), reused 11 (delta 4), pack-reused 47
Receiving objects: 100% (60/60), 8.81 KiB | 2.20 MiB/s, done.
Resolving deltas: 100% (25/25), done.
```
- **Enter the directory**
```bash
student@pod-sandy8-node01:~$ cd latihan01
student@pod-sandy8-node01:~/latihan01$
```
- **Create an image of the previous repository and name it node-exercise01**
```bash
student@pod-sandy8-node01:~/latihan01$ docker build -t node-latihan01 .
[+] Building 85.6s (4/12) docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 569B 0.0s
=> [internal] load metadata for docker.io/library/node:18.13.0 5.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 45B 0.0s
```
- **Run the container with the previously created image and expose the port to 8080**
```bash
student@pod-sandy8-node01:~/latihan01$ docker run -d --rm --name node-latihan01 -p 8080:8080 node-latihan01
15a35d9c5e39684852fbe00d7f30f613b0f83aa3b34085bcf36e8b116bdd56b6
```
- **Try access container**
```bash
student@pod-sandy8-node01:~/latihan01$ curl localhost:8080
Hello World. Wish you were here.
```
**Dockerfile practice**
**Execute in node02**
- **Create latihan02 directory**
```bash
student@pod-sandy8-node02:~$ cd $HOME
student@pod-sandy8-node02:~$ mkdir latihan02
student@pod-sandy8-node02:~$ cd latihan02
student@pod-sandy8-node02:~/latihan02$
```
- **Create Dockerfile as below**
```bash
student@pod-sandy8-node02:~/latihan02$ vim Dockerfile
```

- **Create image From Dockerfile**
```bash
student@pod-sandy8-node02:~/latihan02$ docker build -t docker-whale .
[+] Building 8.0s (3/5) docker:default
=> [internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 174B 0.0s
=> [internal] load metadata for registry.adinusa.id/btacademy/whalesay:latest 4.1s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
```
- **Display the image that has been created**
```bash
student@pod-sandy8-node02:~/latihan02$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-whale latest 5cb6113789b2 6 seconds ago 278MB
```
- **Test run the image**
```bash
student@pod-sandy8-node02:~/latihan02$ docker run docker-whale
_________________________________
/ Men are always ready to respect \
| anything that bores them. |
| |
\ -- Marilyn Monroe /
---------------------------------
\
\
\
## .
## ## ## ==
## ## ## ## ===
/""""""""""""""""___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\______/
```
- **Display the container**
```bash
student@pod-sandy8-node02:~/latihan02$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
student@pod-sandy8-node02:~/latihan02$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f3b96d38f71d docker-whale "/bin/sh -c '/usr/ga…" About a minute ago Exited (0) About a minute ago adoring_leavitt
```
**2. Exploring Dockerfile (Flask Apps)**
**Execute in node01**
**Dockerfile practice**
- **If you don't have a Docker ID, register at https://hub.docker.com/signup**
- **Login with Docker ID**
```bash
student@pod-sandy8-node01:~$ docker login
Log in with your Docker ID or email address to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com/ to create one.
You can log in with your password or a Personal Access Token (PAT). Using a limited-scope PAT grants better security and is required for organizations using SSO. Learn more at https://docs.docker.com/go/access-tokens/
Username: sandyxd18
Password:
WARNING! Your password will be stored unencrypted in /home/student/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
```
- **Create directory latihan03**
```bash
student@pod-sandy8-node01:~$ cd $HOME
student@pod-sandy8-node01:~$ mkdir latihan03
student@pod-sandy8-node01:~$ cd latihan03
student@pod-sandy8-node01:~/latihan03$
```
- **Create file flask**
```bash
student@pod-sandy8-node01:~/latihan03$ vim app.py
```

- **Create file requirements.txt**
```bash
student@pod-sandy8-node01:~/latihan03$ vim requirements.txt
```

- **Creating Dockerfile**
```bash
student@pod-sandy8-node01:~/latihan03$ vim Dockerfile
```

- **Create image from Dockerfile**
```bash
student@pod-sandy8-node01:~/latihan03$ docker build -t flask-latihan03 .
[+] Building 5.7s (4/11) docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 303B 0.0s
=> [internal] load metadata for registry.adinusa.id/btacademy/ubuntu:16.04 3.6s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
```
- **Tag image with docker username**
```bash
student@pod-sandy8-node01:~/latihan03$ docker tag flask-latihan03 sandyxd18/flask-latihan03:latest
```
- **Push image to dockerhub**
```bash
student@pod-sandy8-node01:~/latihan03$ docker push sandyxd18/flask-latihan03:latest
The push refers to repository [docker.io/sandyxd18/flask-latihan03]
387edf65731a: Pushing [==================================================>] 5.748MB
5f70bf18a086: Pushing 1.024kB
ccc4e13922db: Pushing [==================================================>] 4.608kB
```
- **Running the image**
```bash
student@pod-sandy8-node01:~/latihan03$ docker run -d -p 5000:5000 --name flask03 sandyxd18/flask-latihan03
24de3a55da98c37dae6837f9ac3bf8152a75b453e2956ce8e97627f4e228eb6d
```
- **Test browsing**
```bash
student@pod-sandy8-node01:~/latihan03$ curl localhost:5000
Hey, we have Flask in a Docker container!
```
**Tittle 5: Docker Compose**
-
**Introducing Docker Compose**

Docker Compose is a tool provided by Docker for running and organizing containers on a single Docker host. It is used for development, continuous integration, automated testing, etc. The Docker Compose configuration file uses YAML format and is usually called docker-compose.yml. This file is used to describe and run a containerized application, perhaps with multiple containers. A declarative approach means we state what we want from the application without needing to specify specific steps. This differs from the imperative approach, which orders the system step by step.
Docker recommends a declarative approach because it provides ease in managing containerized applications. Docker Compose follows this approach in its configuration.
**1. Using Docker Compose**
**Execute in all node**
- **Download & Install Compose**
```bash
student@pod-sandy8-node01:~$ VERSION=$(curl --silent https://api.github.com/repos/docker/compose/releases/latest | jq .name -r) && \
> DESTINATION=/usr/bin/docker-compose && \
> sudo curl -sL https://github.com/docker/compose/releases/download/${VERSION}/docker-compose-$(uname -s)-$(uname -m) -o $DESTINATION
student@pod-sandy8-node01:~$ sudo chmod 755 $DESTINATION
```
- **Test installation Compose**
```bash
student@pod-sandy8-node01:~$ docker-compose --version
Docker Compose version v2.26.0
```
**Execute in node01**
- **Create a directory my_wordpress and go to the directory**
```bash
student@pod-sandy8-node01:~$ cd $HOME
student@pod-sandy8-node01:~$ mkdir -p latihan/my_wordpress
student@pod-sandy8-node01:~$ cd latihan/my_wordpress
student@pod-sandy8-node01:~/latihan/my_wordpress$
```
- **Create docker-compose file**
```bash
student@pod-sandy8-node01:~/latihan/my_wordpress$ vim docker-compose.yml
```

- **Run compose**
```bash
student@pod-sandy8-node01:~/latihan/my_wordpress$ docker-compose up -d
WARN[0000] /home/student/latihan/my_wordpress/docker-compose.yml: `version` is obsolete
[+] Running 13/34
⠴ db [⠀⣿⣿⣿⣿⣿⡀⣿⠀⠀⠀] Pulling 12.5s
⠋ e83e8f2e82cc Downloading 6.094MB/50.5MB 8.0s
✔ 0f23deb01b84 Download complete 0.8s
```
- **Display the list of containers and test browsing to the wordpress page that has been created**
```bash
student@pod-sandy8-node01:~/latihan/my_wordpress$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4b2806747288 registry.adinusa.id/btacademy/wordpress:latest "docker-entrypoint.s…" 14 seconds ago Up 13 seconds 0.0.0.0:8000->80/tcp, :::8000->80/tcp my_wordpress-wordpress-1
89a173f3434d registry.adinusa.id/btacademy/mysql:5.7 "docker-entrypoint.s…" 14 seconds ago Up 13 seconds 3306/tcp, 33060/tcp my_wordpress-db-1
```
**Tittle 6: Docker Continous Integration (CI)**
-
**1. CI Using Docker**
Continuous Integration (CI) is a practice where developers routinely combine their code into one place, and then the code is automatically checked to detect problems. CI helps in finding bugs faster and makes it easier to fix them.
CI/CD combines the development process with testing, allowing developers to work together to build and test their code. Docker, which can integrate with tools such as Jenkins and GitHub, allows developers to ship and test their code automatically. This helps simplify the development process and save time, while allowing developers to remain productive on other projects.

- The developer submits a commit to GitHub.
- GitHub uses a webhook to notify Jenkins about the update.
- Jenkins pulls in a GitHub repository, including a Dockerfile describing the image, as well as application and test code.
- Jenkins builds a Docker image on the Jenkins slave node.
- Jenkins instantiates the Docker container on the slave node, and runs the appropriate tests.
**2. Docker Hub Automated Build**
Docker Hub can automatically build images from source code in an external repository and automatically push the built images to the Docker repository.
When you set up automatic builds (autobuilds), you create a list of branches and tags that you want to build into a Docker image. Whenever you submit code to one of these branches in a source repository (such as on GitHub) that matches one of the listed image tags, a new build will be triggered using a webhook. This new build will produce a Docker image that will then be pushed to the Docker Hub registry.
This autobuild allows you to automatically build images from build context stored in the repository. This build context usually consists of a Dockerfile and other necessary files. This has advantages, including:
- The image is built according to the specifications you have specified.
- Dockerfiles are available to anyone who has access to your Docker Hub repository.
- Your repository will always be up to date with automatic code changes.
This automated build supports both public and private repositories on GitHub and Bitbucket.
Build Statuses
**Queued**: Waiting for the image to be built.
**Building**: The image building process is in progress.
**Success**: The image has been successfully built without any problems.
**Error**: There was a problem with your image.
**Tittle 7: Docker Swarm & Portainer**
-
**1. What is Swarm?**
Swarm is a collection of computers running Docker, either one or more machines. With swarm mode, Docker gets built-in orchestration and clustering capabilities. Features such as load balancing and service lifecycle management are included. Swarm mode is off by default when running containers with Docker commands, but if enabled, you can manage services rather than containers directly.
**About Docker Swarm**
Docker Swarm is a group of physical or virtual machines that run Docker applications and have been configured to join together in a cluster. Once a group of machines is grouped together, you can still run Docker commands as usual, but now they will be executed by the machines in your cluster. Cluster activity is controlled by the swarm manager, and the machines that have joined the cluster are called nodes.

Docker Swarm Features:
- Integrated cluster management with Docker Engine: Use the Docker Engine CLI to create clusters from Docker Engines where you can deploy application services without the need for additional orchestration software.
- Decentralized design: Docker Engine handles specialization at runtime, allowing you to deploy both types of nodes (managers and workers) from a single disk image.
- Declarative service model: Docker Engine uses a declarative approach to define the state of services in your application stack.
- Scaling: You can declare the number of tasks for each service and swarm manager automatically adjusts the number of tasks as needed.
- Desired state reconciliation: Swarm manager monitors the state of the cluster and resolves differences between the actual and desired state.
- Multi-host network: You can define an overlay network for your service and swarm manager automatically assigns addresses to containers.
- Service discovery: Each service in the swarm is given a unique DNS name and is selected to load running containers.
- Load balancing: You can expose service ports to an external load balancer and define how to distribute service containers between nodes internally.
- Security by default: Each node implements TLS mutual authentication and encryption to secure communications between nodes.
- Incremental updates: You can apply service updates to nodes in stages by controlling the delay between service deployments to each set of nodes.
**Alternative container orchestration**
- **Kubernetes**

Kubernetes is an open-source platform used to manage containerized application workloads, as well as providing declarative configuration and automation. Kubernetes sits within a large and fast-growing ecosystem. Kubernetes service, support, and tools are widely available.
- **OpenShift**

Red Hat OpenShift is a cloud-based Kubernetes platform that helps developers build applications. It offers automated installation, upgrades, and life cycle manageme
**2. Portainer for Docker**
**About Portainer**
Portainer is a popular container management tool with many users and extensive GitHub support. It lets you manage Docker containers and Swarm clusters with a light and simple interface. Portainer can run on multiple platforms and makes it easy to manage your Docker resources such as containers, images, and networking. With an easy-to-understand interface, Portainer is suitable for administrators and developers of all skill levels.

**3. Create Swarm**
**Execute in node01**
- **Initialization Docker Swarm**
```bash
student@pod-sandy8-node01:~$ docker swarm init --advertise-addr 10.7.7.10
Swarm initialized: current node (1y31gdei4uolojyh7elo6khc8) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-1eqb5cevnu8x1tl8e13xtv5yeftnp8usho573c631jpcszb3lf-7oou9hao4w2s2ozioavg0ch9l 10.7.7.10:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
```
**Execute in node02**
- **Copy command docker join**
```bash
student@pod-sandy8-node02:~$ docker swarm join --token SWMTKN-1-1eqb5cevnu8x1tl8e13xtv5yeftnp8usho573c631jpcszb3lf-7oou9hao4w2s2ozioavg0ch9l 10.7.7.10:2377
This node joined a swarm as a worker.
```
**Execute in node01**
- **Check if node02 already join**
```bash
student@pod-sandy8-node01:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
1y31gdei4uolojyh7elo6khc8 * pod-sandy8-node01 Ready Active Leader 26.0.0
u0wgeqh4czdr7wbjud4ep895u pod-sandy8-node02 Ready Active 26.0.0
```
**4. Deploy Service to Swarm**
**Execute in node01**
- **Create Service Nginx with 2 replica and expose port to 80**
```bash
student@pod-sandy8-node01:~$ docker service create --name web --replicas 2 -p 80:80 registry.adinusa.id/btacademy/nginx:latest
```
- **Check Service Running Correctly in all node**
```bash
student@pod-sandy8-node01:~$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
dq5mx5e6iz2e web replicated 2/2 registry.adinusa.id/btacademy/nginx:latest *:80->80/tcp
```
- **Test Browsing From node01 and node02**
```bash
student@pod-sandy8-node01:~$ curl http://10.7.7.10
student@pod-sandy8-node02:~$ curl http://10.7.7.20
```
- **To check information about the service**
```bash
student@pod-sandy8-node01:~$ docker service inspect --pretty web
ID: dq5mx5e6iz2e6hityqnv5eblf
Name: web
Service Mode: Replicated
Replicas: 2
Placement:
UpdateConfig:
Parallelism: 1
On failure: pause
```
- **If we want to check where the service is running**
```bash
student@pod-sandy8-node01:~$ docker service ps web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
ro4mrhf4vm10 web.1 registry.adinusa.id/btacademy/nginx:latest pod-sandy8-node02 Running Running 7 minutes ago
4puadtin6skr web.2 registry.adinusa.id/btacademy/nginx:latest pod-sandy8-node01 Running Running 7 minutes ago
```
- **Create container with limit cpu and limit Memory**
```bash
student@pod-sandy8-node01:~$ docker service create --name sandyxd18 --reserve-cpu 1 --limit-cpu 1 --reserve-memory 256mb --limit-memory 128mb registry.adinusa.id/btacademy/httpd:latest
```
- **Check the container Spesification**
```bash
student@pod-sandy8-node01:~$ docker service inspect --pretty sandyxd18
ID: oja9dla6ks26g74xxmxfigc52
Name: sandyxd18
Service Mode: Replicated
Replicas: 1
```
**5. Docker swarm Scale & Update**
**Execute in node01**
- **Create Service Nginx with 3 replica**
```bash
student@pod-sandy8-node01:~$ docker service create --name web2 --replicas 3 -p 80:80 registry.adinusa.id/btacademy/nginx:latest
```
- **We can change the replica of the service**
```bash
student@pod-sandy8-node01:~$ docker service scale web2=1
web2 scaled to 1
```
- **Check if replica already change**
```bash
student@pod-sandy8-node01:~$ docker service ps web2
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
g8cjqi0omqf6 web2.1 registry.adinusa.id/btacademy/nginx:latest pod-sandy8-node02 Running Running 2 minutes ago
```
- **Docker swarm can rolling update the service**
```bash
student@pod-sandy8-node01:~$ docker service update --image sistyo/myweb web2
```

**6. Install Portainer and configuration**
**Execute in node01**
- **Install Portainer In Node01**
```bash
student@pod-sandy8-node01:~$ docker volume create portainer_data
portainer_data
student@pod-sandy8-node01:~$ docker run -d -p 8000:8000 -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest
```
- **Access Portainer Dashboard**
Open browser and access to http://10.10.10.11:9000

- **Connect Portainer Agent Node02 to Portainer Dashboard**
Click menu Environments -> Add environmets

Select Docker Swarm -> Start Wizard

Select Agent -> Copy command to run in node01

**7. Running Container from Portainer**
- **Access Portainer dashboard**
Access to http://10.10.10.11:9000

- **Running Container**
In Home, choose node02
Click Containers -> Add Container

Fill in the name column with [username]-web
Fill the Image Coloumn with nginx:latest
Node pod-username-node02

Click Deploy the Container

- **Access to container**
Access to http://10.10.10.12:8080

**7. Build & Push Image from Portainer**
- **Create image from Dockerfile**
Cick Menu Image -> + Build a new Image

Fill name coloumn with {username adinusa}/nginx:lab76

Select build method to Web Editor

Deployment to pod-username-node01 and Click Build the image

- **Attach image to Docker Hub**
Click menu Registries -> Add registry

In menu registry provider -> Select DockerHub
Name: repo-{username adinusa}
Username: {username docker}
Password: {password docker}
Click Add Registry

Back to Images, Open the previously created image
in Registry coloumn select repo-username adinusa
In Image coloumn fill with {username docker}/nginx:lab76 -> Click Tag
Select Push to Registry
**Tittle 8: Logging Driver**
-
Driver logging is a feature in Docker that helps you view information from running containers. Every Docker has a default logging driver. Automatically, Docker uses the json-file logging driver, which stores container logs in JSON format. You can also use the driver logging plugin for more options.
By default, Docker does not perform log rotation, which can cause json-file log files to take up a lot of disk space if the container produces a lot of output.
Docker still uses json-files as default to maintain compatibility with older versions and when used with Kubernetes.
**1. Configuring Logging Driver**
**Execute in node01**
- **Create daemon.json file**
```bash
student@pod-sandy8-node01:~$ sudo vim /etc/docker/daemon.json
```

- **Restart Daemon dan Docker**
```bash
student@pod-sandy8-node01:~$ sudo systemctl daemon-reload
student@pod-sandy8-node01:~$ sudo systemctl restart docker
```
- **Run container**
```bash
student@pod-sandy8-node01:~$ docker run --log-driver json-file --log-opt max-size=10m registry.adinusa.id/btacademy/alpine echo hello world
```
- **Check the logs in the docker directory**
```bash
student@pod-sandy8-node01:~$ sudo cat /var/lib/docker/containers/$(docker ps --no-trunc -a | grep 'alpine' | awk '{print $1}')/$(docker ps --no-trunc -a | grep 'alpine' | awk '{print $1}')-json.log | jq .
```
**Tittle 9: Health Check**
-
The HEALTHCHECK instruction tells Docker how to test containers to check whether they are still functional. This can detect cases such as a web server being stuck in an infinite loop and unable to handle new connections, even though the server process is still running.
When a container has a health check defined, the container has a health state other than its normal state. This status is initially started. Each time a health check passes, the container will become healthy (whatever its previous state). After a number of consecutive failures, the container becomes unhealthy.
**1. Health Check**
**Execute in node01**
- **Create working directory**
```bash
student@pod-sandy8-node01:~$ cd $HOME
student@pod-sandy8-node01:~$ mkdir hc-latihan01
student@pod-sandy8-node01:~$ cd hc-latihan01
student@pod-sandy8-node01:~/hc-latihan01$
```
- **Create Dockerfile**
```bash
student@pod-sandy8-node01:~/hc-latihan01$ vim Dockerfile
```

- **Create image from Dockerfile**
```bash
student@pod-sandy8-node01:~/hc-latihan01$ docker build -t http-healthcheck .
```
- **Run image**
```bash
student@pod-sandy8-node01:~/hc-latihan01$ docker run -d -p 80:80 --name http-healthcheck http-healthcheck
```
- **Check running container**
```bash
student@pod-sandy8-node01:~/hc-latihan01$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
162ba8ed10a9 http-healthcheck "/app" 5 minutes ago Up 5 minutes (healthy) 0.0.0.0:80->80/tcp, :::80->80/tcp http-healthcheck
```
- **Check with curl**
```bash
student@pod-sandy8-node01:~/hc-latihan01$ curl http://localhost
<h1>A healthy request was processed by host: 162ba8ed10a9</h1>
```
- **Check for unhealthy**
```bash
student@pod-sandy8-node01:~/hc-latihan01$ curl http://localhost/unhealthy
```
**Health Check practice**
- **Create a new directory**
```bash
student@pod-sandy8-node01:~$ cd $HOME
student@pod-sandy8-node01:~$ mkdir hc-latihan02
student@pod-sandy8-node01:~$ cd hc-latihan02
student@pod-sandy8-node01:~/hc-latihan02$
```
- **Create server.js file**
```bash
student@pod-sandy8-node01:~/hc-latihan02$ vim server.js
```

- **Create Dockerfile**
```bash
student@pod-sandy8-node01:~/hc-latihan02$ vim Dockerfile
```

- **Create image from dockerfile**
```bash
student@pod-sandy8-node01:~/hc-latihan02$ docker build -t node-server .
```
- **Run image**
```bash
student@pod-sandy8-node01:~/hc-latihan02$ docker run -d –name nodeserver -p 8080:8080 -p 8081:8081 node-server
```
- **Check running container**
```bash
student@pod-sandy8-node01:~/hc-latihan02$ curl 127.0.0.1:8080
OK
student@pod-sandy8-node01:~/hc-latihan02$ curl 127.0.0.1:8081
Shutting down…
```
**Tittle 10: Security**
-
**1. Kernel Namespaces**
Docker containers are very similar to LXC containers, and have similar security features. When starting a container by running docker, behind the scenes, Docker creates a set of namespaces and control groups for the container. Namespaces provide the first and easiest form of isolation: processes running inside a container cannot see, and do not even affect, processes running in other containers, or on the host system. Each container also gets its own networking stack, meaning that a container doesn't get privileged access to another container's sockets or interfaces. Of course, if the host system is set up correctly, containers can interact with each other through their respective network interfaces - just as they interact with external hosts. When you specify a public port for your containers or use a link, IP traffic is allowed between containers. They can ping each other, send/receive UDP packets, and establish TCP connections, but can be restricted if necessary. From a network architecture perspective, all containers on a Docker host reside on a bridge interface. This means that they are like physical machines connected via a common Ethernet switch; nothing more, nothing less.
**2. Control Groups**
Control Groups are another key component of Linux Containers. This group enforces calculations and resource limitations. These groups provide many useful metrics, but also help ensure that each container gets its fair share of memory, CPU, disk I/O; and, more importantly, that a single container cannot crash the system by consuming any of these resources. So, while they don't play a role in preventing one container from accessing or affecting another container's data and processes, they are critical to fending off some denial-of-service attacks. They are especially important on multi-tenant platforms, such as public and private PaaS, to guarantee consistent uptime (and performance) even when some applications start to misbehave.
Docker containers, by default, are quite secure, especially if you run your processes as an unprivileged user inside the container.
**3. CIS Docker Benchmark**
CIS creates best practices for cyber security and defense. CIS uses crowdsourcing to determine its security recommendations. CIS Benchmark is one of the most popular tools.
Organizations can use CIS Benchmark for Docker to validate that their Docker containers and Docker runtime are configured as securely as possible. There are commercial and open source tools that can automatically check your Docker environment against the recommendations set out in the CIS Benchmark for Docker to identify unsafe configurations.
CIS Benchmark for Docker provides a number of useful configuration checks, but organizations should consider it a starting point and go beyond the CIS checks to ensure best practices are implemented. Setting resource limits, reducing privileges, and ensuring images run in read-only mode are some examples of additional checks you need to run on your container files.
**4. Secure Computing Mode**
Safe computing mode (seccomp) is a Linux kernel feature. You can use it to limit the actions available within a container. The seccomp() system call operates on the seccomp state of the calling process. You can use this feature to restrict your app's access.
**5. Secret**
Secrets are blobs of data that should not be sent over a network or stored unencrypted in a Dockerfile or in your application's source code.
**Tittle 11: Storage Driver**
-
**1. Docker Storage Drivers**
The storage driver plays a role in providing users with access to the writeable container layer. The storage driver also plays a role in storing and managing images and containers on the user's Docker host. The following storage drivers can be used in Docker:
**overlay2**: driver for all Linux distributions and requires no additional configuration.
**aufs**: driver for Docker 18.06 and below, when running on Ubuntu which does not support overlay2.
**fuse-overlayfs**: to run Rootless Docker on hosts that do not provide support for rootless overlay2.
**devicemapper**:can be run but requires direct-lvm for production environments, because loopback-lvm, even with zero configuration, has very poor performance.
**btrfs and zfs**: storage is used if there is a supporting file system that allows advanced options, such as creating “snapshots”.
**vfs**: storage is intended for testing purposes, and for situations
**2. Configuring Storage Driver**
**Execute in node01**
- **Edit file daemon.json**
```bash
student@pod-sandy8-node01:~$ sudo vim /etc/docker/daemon.json
```

- **Restart service docker**
```bash
student@pod-sandy8-node01:~$ sudo service docker restart
```
- **Check docker info**
```bash
student@pod-sandy8-node01:~$ docker info
```
- **Check with docker pull**
```bash
student@pod-sandy8-node01:~$ docker pull registry.adinusa.id/btacademy/ubuntu
```
- **Check the docker directory**
```bash
student@pod-sandy8-node01:~$ sudo ls -al /var/lib/docker/vfs/dir/
total 60
drwx--x--- 15 root root 4096 Mar 29 03:13 .
drwx--x--- 3 root root 4096 Mar 29 03:11 ..
drwxr-xr-x 17 root root 4096 Mar 29 03:13 1b598df1567f59ede588f8b94cfada8cdbee7959c00cd5ec8d8e07d753eb202f
drwxr-xr-x 5 root root 4096 Mar 29 03:12 1ec5e020a1ff0ed5709fb7cabd0a0fb2d648f5acd2441f7b8b9e698dcc8d5e84
student@pod-sandy8-node01:~$ sudo du -sh /var/lib/docker/vfs/dir/
1.6G /var/lib/docker/vfs/dir/
```
**Tittle 12: Logging and Error Handling**
-
The docker logs command displays information logged by running containers. The docker service logs command displays information logged by all containers participating in a service. The information logged and the format of the log depend almost entirely on the container's final command.
By default, the docker logs command displays command output as it would in the terminal. However, in some cases, the information displayed may not be useful. For example, if you use a logging driver that sends logs elsewhere or if a containerized application doesn't send output to STDOUT and STDERR. In such cases, you need to take additional steps.
One commonly used solution is to create a symbolic link from the log file to STDOUT and STDERR. This can be done by changing the application configuration in the Docker image. For example, the official nginx image creates a symbolic link from the log file to the appropriate custom device.
However, it's important to remember that docker logs only show what is sent to STDOUT and STDERR. If there are other settings for logging, it may require a different way to view the logs
**1. Log Check**
- **Check history image**
```bash
student@pod-sandy8-node01:~$ docker history registry.adinusa.id/btacademy/nginx:latest
```
- **Run nginx**
```bash
student@pod-sandy8-node01:~$ docker run -dit -p 80:80 –name nginx1 registry.adinusa.id/btacademy/nginx
```
- **Check the filesystem on nginx**
```bash
student@pod-sandy8-node01:~$ docker diff nginx1
```
- **Check log**
```bash
student@pod-sandy8-node01:~$ docker logs –details nginx1
student@pod-sandy8-node01:~$ docker logs –timestamps nginx1
student@pod-sandy8-node01:~$ docker logs nginx1
```