---
# System prepended metadata

title: Docker Fundamental

---

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

![image](https://hackmd.io/_uploads/SklT5rnRp.jpg)
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-Logo](https://hackmd.io/_uploads/S1CM3B30T.png)

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-logo](https://hackmd.io/_uploads/rJ653HhCp.png)

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-horizontal-color](https://hackmd.io/_uploads/B1FgaS3Rp.png)

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**
![architecture-docker](https://hackmd.io/_uploads/H1lryU3Ap.svg)

**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**
![image](https://hackmd.io/_uploads/r1kaME0Ra.png)
```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
![image](https://hackmd.io/_uploads/BkT7i4RRT.png)

**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/
![image](https://hackmd.io/_uploads/ryOKyBCRa.png)

**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.
![H158FiRaa](https://hackmd.io/_uploads/HkwvmIC0p.png)
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.
![ByJdKiC6T](https://hackmd.io/_uploads/SJzt7LRCp.png)

**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.
![HynH7xy0p](https://hackmd.io/_uploads/r1JHM-1y0.png)

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.
![S1Yqmey06](https://hackmd.io/_uploads/Sy_wG-1J0.png)

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.
![ByF8BeyR6](https://hackmd.io/_uploads/ryEpGZyy0.png)

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
```
![image](https://hackmd.io/_uploads/ryr-IZJyA.png)

- **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
```
![image](https://hackmd.io/_uploads/SyAzFZkJR.png)

- **Create file requirements.txt**
```bash
student@pod-sandy8-node01:~/latihan03$ vim requirements.txt
```
![image](https://hackmd.io/_uploads/HJuQT-k10.png)

- **Creating Dockerfile**
```bash
student@pod-sandy8-node01:~/latihan03$ vim Dockerfile
```
![image](https://hackmd.io/_uploads/S1ePc-kkR.png)

- **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**
![MainImage-2](https://hackmd.io/_uploads/rk9iTG1JA.jpg)

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
```
![image](https://hackmd.io/_uploads/r1BL0_y10.png)

- **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.
![rk_FNBJAp](https://hackmd.io/_uploads/H1_uAd1JA.png)

- 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.
![1 cGtPijc0aQU0lRYq2SEFpw](https://hackmd.io/_uploads/H1mYeKkkC.png)

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**
![0 0upfXtjqscQ5NQfN](https://hackmd.io/_uploads/rJ0ZVFkkR.png)
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**
![OpenShift-1](https://hackmd.io/_uploads/SJ5eStkyR.png)
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.
![Untitled](https://hackmd.io/_uploads/SJaTUK1k0.png)

**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
```
![image](https://hackmd.io/_uploads/HyEJ0Yy1R.png)

**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
![image](https://hackmd.io/_uploads/HJWhkqJkA.png)

- **Connect Portainer Agent Node02 to Portainer Dashboard**
Click menu Environments -> Add environmets
![image](https://hackmd.io/_uploads/rJ851-gJR.png)
Select Docker Swarm -> Start Wizard
![image](https://hackmd.io/_uploads/SJl3kZx1C.png)
Select Agent -> Copy command to run in node01
![image](https://hackmd.io/_uploads/BJtAgblJ0.png)

**7. Running Container from Portainer**
- **Access Portainer dashboard**
Access to http://10.10.10.11:9000
![image](https://hackmd.io/_uploads/BkXz-Wg10.png)

- **Running Container**
In Home, choose node02
Click Containers -> Add Container
![image](https://hackmd.io/_uploads/B1WrGbgyC.png)
Fill in the name column with [username]-web
Fill the Image Coloumn with nginx:latest
Node pod-username-node02
![image](https://hackmd.io/_uploads/SkE-mZe1A.png)
Click Deploy the Container
![image](https://hackmd.io/_uploads/rytBQ-xkA.png)

- **Access to container**
Access to http://10.10.10.12:8080
![image](https://hackmd.io/_uploads/r16sQ-xk0.png)

**7. Build & Push Image from Portainer**
- **Create image from Dockerfile**
Cick Menu Image -> + Build a new Image
![image](https://hackmd.io/_uploads/rJ-_BZlkA.png)
Fill name coloumn with {username adinusa}/nginx:lab76
![image](https://hackmd.io/_uploads/SkzTSZlJR.png)
Select build method to Web Editor
![image](https://hackmd.io/_uploads/HJmDLZlkR.png)
Deployment to pod-username-node01 and Click Build the image
![image](https://hackmd.io/_uploads/SybYU-l1C.png)

- **Attach image to Docker Hub**
Click menu Registries -> Add registry
![image](https://hackmd.io/_uploads/Hkxzw-xJ0.png)
In menu registry provider -> Select DockerHub
Name: repo-{username adinusa}
Username: {username docker}
Password: {password docker}
Click Add Registry
![image](https://hackmd.io/_uploads/B1ddPblJC.png)
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
```
![image](https://hackmd.io/_uploads/BkWK5Wl10.png)

- **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
```
![image](https://hackmd.io/_uploads/HkXCd9X1A.png)

- **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
```
![image](https://hackmd.io/_uploads/HyaFGoQyR.png)

- **Create Dockerfile**
```bash
student@pod-sandy8-node01:~/hc-latihan02$ vim Dockerfile
```
![image](https://hackmd.io/_uploads/r1KcSjX10.png)

- **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
```
![image](https://hackmd.io/_uploads/BywCx2XJA.png)

- **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
```