[Docker][Summary]

·17 min read

01-01_FCND]

01-02_JOC]

01-03_Why is Docker?] : 일반적인 software 사용을 위한 설치과정에서 격는 어려움이 존재한다

  • 일반적으로 software를 설치하기 위해서는 아래와 같은 절차가 필요하다

  • 그리고 설치과정에는 에러를 마주할 가능성이 있고, 이를 해결하기 위해서는 상당히 시간과 비용이 필요할 수 있다

  • 도커는 이러한 문제에 대한 해결책을 제시한다

    image

    image

01-04_What is Docker?] : Docker를 왜 사용하지를 알았고, 그럼 Docker는 뭐하는 놈인가?

  • Docker는 Docker 생태계를 말하며, Docker를 사용한다는 것은 생태계가 제공하는 여러 utilities를 사용하고 있다는 것을 말한다

  • Docker를 통해, 최종적으로 생성된 container는 Image로부터 생성된 하나의 프로그램이다

    image

    image

01-05_Dcoker for Mac/Windows]

  • Docker를 사용하기 위해서, Docker Client가 필요하고 각 PC 운영체제에 맞게 설치해야 한다

  • Docker Client(Docker CLI)는 원하는 Docker 명령을 실행시키도록 도와주는 Tools이다

    image

**01-06_Installing **Docker on macOS]

**01-07_Installing **Docker with WSL on Windows 10/11]

**01-08_Installing **Docker on Linux]

01-09_Using the Docker Client**]**

  • docker client를 설치했다면, docker 명령어를 docker server로 전달할 수 있다
  • docker version : version명령으로 server 정보를 확인할 수 있다, Server는 linux/arm64를 사용하고 있다걸 확인할 수 있다

➜  ~ docker version Client: Cloud integration: v1.0.35+desktop.10 Version:           25.0.2 API version:       1.44 Go version:        go1.21.6 Git commit:        29cf629 Built:             Thu Feb  1 00:18:45 2024 OS/Arch:           darwin/arm64 Context:           desktop-linux

Server: Docker Desktop 4.27.1 (136059) Engine:   Version:          25.0.2   API version:      1.44 (minimum version 1.24)   Go version:       go1.21.6   Git commit:       fce6e0c   Built:            Thu Feb  1 00:23:21 2024   OS/Arch:          linux/arm64   Experimental:     false containerd:   Version:          1.6.28   GitCommit:        ae07eda36dd25f8a1b98dfbf587313b99c0190bb runc:   Version:          1.1.12   GitCommit:        v1.1.12-0-g51d5e94 docker-init:   Version:          0.19.0   GitCommit:        de40ad0 ➜  ~

  • $ docker run hello-world 명령시 어떠한 일이 일어날까? >> Docker Server가 Image Cache에 저장된 image 존재유무를 확인하고, 없다면 Docker Hub에서 가져온다

    image

01-10_But Really...What's a Container**]**

  • container의 동작 원리를 알기 위해서, Operating System에 대해 어느 정도 이해가 필요하다

  • 대부분의 OS는 Kernel을 가지고 있는데, kernel은 모든 programs이 HW 컴퓨터 자원(CPU, Memory, Hard Dist etc...)에 대한 사용 권한을 매니징하는 역할을 수행한다

  • 예를 들어, NodeJS program이 Hard Disk에 특정 내용을 저장하고 싶다는 System Call을 통해 Kernel에 Hard Disk로 접근 요청을 해야 한다  

    image

  • 다른 예로, Python v2를 사용하는 Chrome과 Python v3를 사용하는 NodeJS가 있는데, Hard Disk에 접근은 v2만 가능한 상황이다

  • 어떻게 이 문제를 해결해야 하나?

    image

  • HW(Hard Disk)를 namespacing을 사용해야 하는데, Segment를 분리해서 연결시켜야 한다

  • 이를 통해 Chrome은 V2에 접근하게 하고, NodeJS는 V3에 접근하게 한다

    image

 

  • 결국, 하나의 장비에서 Chrome과 NodeJS가 운영될 수 있다

    image

  • Namespacing이란 process(program)당 Isolated된 HW를 할당받아 사용하게 만드는 걸 말한다

  • Control Groups(cgroups)이란 process(program)당 자원의 사용이 제한되어 동시에 사용이 불가한 자원으로 포트가 이에 해당한다  

    image

  • 그리하여, 아래 점선으로 표기된 부분은 Chrome이 Isolated된 영역을 이용하는 모습을 보여준다  

    image

  • 좀 더 구체화한 모습은 아래와 같다

    image

  • 실제적으로, Chome을 실행하는 Container가 있다고 했을 때

  • 아래 그림과 같이, [FS Snapshot]이 Hard Disk로 Copy되고 Chrome 프로그램이 실행된다.

    image

**01-11_How's **Docker Running on Your Computer]

  • docker client를 설치했고, container를 실행시켰다는 것은 Linux Virtual Machine에서 process(container)가 run한다는 의미다

    image

02-12_Docker Run in Detail**]**

  • Docker Container를 실행하기

  • $ docker run <image name>

  • Image에 정의된 "hello-world"라는 binary가 Linux-Virtual-Machine에 있는 hard disk 저장되고, binary가 실행된다

  • 여기서, Default Command가 실행된 것이다

  • Container에 process가 looping하지 않은 process는 exit(종료)되고, looping하는 process는 up(running)상태로 남는다

    image

    image

02-13_Overriding Default Commands**]**

  • 기본 명령어를 지정하는 방법이 있다
  • $ docker run <image name> <command>
  • Startup Command가 <command>로 지정된다

 

image

   

image

02-14_Listing Running Containers**]**

  • container(process) 리스트를 보여준다

  • $ docker ps :  status가 up으로 running 상태의 container를 보여준다

  • $ docker ps -a : 모든 상태의 container를 보여준다

    image

02-15_Container Lifecycle**]**

  • container(process) 리스트를 봤는데, 왜 shutdown(exit)되는가?
  • 먼저, docker run 은 docker create(container 생성) + docker start(container 실행)을 의미한다
  • container가 생성되고 startup command로 process가 끝나면 container(process)가 shutdown된다
  • $ docker start -a <container id> :  -a는 Attach STDOUT/STDERR and forward signals

➜  ~ docker create hello-world d617efa3c329824b2a171472b71bcf1eefca05a76201c770d0280aa3a8460105 ➜  ~ docker start -a d617efa3c329824b2a171472b71bcf1eefca05a76201c770d0280aa3a8460105

Hello from Docker! This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:

  1. The Docker client contacted the Docker daemon.
  2. The Docker daemon pulled the "hello-world" image from the Docker Hub.     (arm64v8)
  3. The Docker daemon created a new container from that image which runs the     executable that produces the output you are currently reading.
  4. The Docker daemon streamed that output to the Docker client, which sent it     to your terminal.

To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/

For more examples and ideas, visit: https://docs.docker.com/get-started/

➜  ~  

image

 

image

02-16_Restarting Stopped Container**]**

  • $ docker run busybox echo hi there 로 container를 생성했다
  • 해당 container는 exited 상태이고, 다시 실행을 위해 $ docker start <container id> 명령으로 재실행이 가능하다
  • $ docker start -a <container id>로 STDOUT을 볼 수 있다
  • $ docker start -a <container id> echo bye there은 start 사용법상 여러 <container id>가 나열되어야 한다

➜  ~ docker run busybox echo hi there Unable to find image 'busybox:latest' locally latest: Pulling from library/busybox 835f85a6d665: Pull complete Digest: sha256:c230832bd3b0be59a6c47ed64294f9ce71e91b327957920b6929a0caa8353140 Status: Downloaded newer image for busybox:latest hi there ➜  ~ docker ps -a CONTAINER ID   IMAGE     COMMAND           CREATED         STATUS                     PORTS     NAMES a8da300f416a   busybox   "echo hi there"   5 seconds ago   Exited (0) 4 seconds ago             focused_varahamihira ➜  ~ docker start a8da300f416a a8da300f416a ➜  ~ docker start -a a8da300f416a hi there ➜  ~ docker start -a a8da300f416a echo bye there you cannot start and attach multiple containers at once ➜  ~ docker start --help

Usage:  docker start [OPTIONS] CONTAINER [CONTAINER...]

Start one or more stopped containers

Aliases:   docker container start, docker start

Options:   -a, --attach               Attach STDOUT/STDERR and forward signals       --detach-keys string   Override the key sequence for detaching a container   -i, --interactive          Attach container's STDIN ➜  ~

02-17_Removing Stopped Container**]**

  • $ docker system prune : 불필요한 container, image, cache, network 등을  삭제한다
  • docker 작업을 마치고, 추가 작업이 없는 경우 자원을 낭비하지 않도록 해당 명령을 수행하자

➜  ~ docker system prune WARNING! This will remove:   - all stopped containers   - all networks not used by at least one container   - all dangling images   - unused build cache

Are you sure you want to continue? [y/N] y Deleted Containers: 5ec79aa7b10d6e4660bafe74a9a97b8412c18d45f24dc5b0fd2d287ce70abed3 a8da300f416ac1a930c00177c37ac360c78cde9bb67f8692dda9ec78d654975b

Total reclaimed space: 0B ➜  ~

02-18_Retrieving Log Output**]**

  • $ docker logs <container id> : Fetch the logs of a container

    image

➜  ~ docker create busybox echo hi there 932b3a005c553eeb6c941cd31850c76c80f7888222f114feb37a771d1c8d9fca ➜  ~ docker start 932b3a005c553eeb6c941cd31850c76c80f7888222f114feb37a771d1c8d9fca 932b3a005c553eeb6c941cd31850c76c80f7888222f114feb37a771d1c8d9fca ➜  ~ docker logs 932b3a005c553eeb6c941cd31850c76c80f7888222f114feb37a771d1c8d9fca hi there ➜  ~ docker start 932b3a005c553eeb6c941cd31850c76c80f7888222f114feb37a771d1c8d9fca 932b3a005c553eeb6c941cd31850c76c80f7888222f114feb37a771d1c8d9fca ➜  ~ docker logs 932b3a005c553eeb6c941cd31850c76c80f7888222f114feb37a771d1c8d9fca hi there hi there ➜  ~

02-19_Stopping Containers**]**

  • 계속 Status: UP(running) 중인 container를 중지시키는 방법

    image

    image

    image

02-20_Multi-Command Containers**]**

  • redis-server가 돌고 있는 container에 외부에서 redis-cli를 실행해도 바로 container 내 redis-server와 연결할 수 없다

    image

02-21_Executing Commands in Running Containers**]**

  • 그렇다면, redis-server가 Status:UP(running)인 container에 명령을 실행시킬 수 있다

  • $ docker exec -it <container id> <command>

    image

    image

➜  ~ docker run redis Unable to find image 'redis:latest' locally latest: Pulling from library/redis 92c3b3500be6: Pull complete 631720f833ee: Pull complete 704a08909867: Pull complete 090311ee98f0: Pull complete 50eb2e3e87d6: Pull complete 4a05d8378bf0: Pull complete 4f4fb700ef54: Pull complete 713e6192e133: Pull complete Digest: sha256:eadf354977d428e347d93046bb1a5569d701e8deb68f090215534a99dbcb23b9 Status: Downloaded newer image for redis:latest 1:C 18 Sep 2024 11:22:16.175 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo 1:C 18 Sep 2024 11:22:16.175 * Redis version=7.4.0, bits=64, commit=00000000, modified=0, pid=1, just started 1:C 18 Sep 2024 11:22:16.175 # 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 18 Sep 2024 11:22:16.175 * monotonic clock: POSIX clock_gettime 1:M 18 Sep 2024 11:22:16.176 * Running mode=standalone, port=6379. 1:M 18 Sep 2024 11:22:16.176 * Server initialized 1:M 18 Sep 2024 11:22:16.176 * Ready to accept connections tcp

^Z [1]  + 13309 suspended  docker run redis ➜  ~ docker ps -a CONTAINER ID   IMAGE     COMMAND                   CREATED          STATUS                      PORTS      NAMES 882dfc420465   redis     "docker-entrypoint.s…"   26 seconds ago   Up 24 seconds               6379/tcp   thirsty_elgamal ➜  ~ docker exec -it 882dfc420465 redis-cli 127.0.0.1:6379> set myvalue 5 OK 127.0.0.1:6379> get myvalue "5" 127.0.0.1:6379>

02-22_The Purpose of the IT Flag**]**

  • $ docker exec -it에서 이 flag들의 의미는?

  • -i : terminal을 통해 process와 STDIN를 전달하고, STDOUT STDERR를 받는다

  • -t : Allocate a pseudo-TTY (보기 좋게 표시해준다)

    image

02-23_Getting a Command Prompt in a Container**]**

  • 매번 container에 exec로 명령을 수행할 필요없이, shell command로 container에 접근해 명령을 수행할 있다

    image

➜  ~ docker ps -a CONTAINER ID   IMAGE     COMMAND                   CREATED          STATUS                      PORTS      NAMES 882dfc420465   redis     "docker-entrypoint.s…"   11 minutes ago   Up 10 minutes               6379/tcp   thirsty_elgamal 932b3a005c55   busybox   "echo hi there"           41 minutes ago   Exited (0) 41 minutes ago              sad_rubin ➜  ~ docker exec -it 882dfc420465 bash root@882dfc420465:/data# redis-cli 127.0.0.1:6379> get myvalue "5" 127.0.0.1:6379>

02-24_Starting with a Shell**]**

  • container를 실행할때, shell이 FS snapshot에 있는 경우 바로 실행시킬 수 있다
  • $ docker run -it busybox sh

➜  ~ docker run -it busybox sh / # ls bin    dev    etc    home   lib    lib64  proc   root   sys    tmp    usr    var / #

image

02-25_Container Isolation**]**

  • 생성된 container는 Isolated 상태로 서로 영향을 주지 않는 독립 공간이다

➜  ~ docker ps -a CONTAINER ID   IMAGE     COMMAND                   CREATED          STATUS                      PORTS      NAMES 3ec31ad00755   busybox   "sh"                      13 seconds ago   Up 13 seconds                          hardcore_gould 1632d24b635e   busybox   "sh"                      7 minutes ago    Up 7 minutes                           sweet_dewdney ➜  ~

[CONTAINER ID : 3ec31ad00755] / # ps -ef PID   USER     TIME  COMMAND     1 root      0:00 sh    10 root      0:00 ps -ef / # ifconfig eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:03             inet addr:172.17.0.3  Bcast:172.17.255.255  Mask:255.255.0.0           UP BROADCAST RUNNING MULTICAST  MTU:65535  Metric:1           RX packets:13 errors:0 dropped:0 overruns:0 frame:0           TX packets:0 errors:0 dropped:0 overruns:0 carrier:0           collisions:0 txqueuelen:0           RX bytes:1006 (1006.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback             inet addr:127.0.0.1  Mask:255.0.0.0           UP LOOPBACK RUNNING  MTU:65536  Metric:1           RX packets:0 errors:0 dropped:0 overruns:0 frame:0           TX packets:0 errors:0 dropped:0 overruns:0 carrier:0           collisions:0 txqueuelen:1000           RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # ls bin    dev    etc    home   lib    lib64  proc   root   sys    tmp    usr    var / # touch con3ec31ad00755 / # ls bin              dev              home             lib64            root             tmp              var con3ec31ad00755  etc              lib              proc             sys              usr / #

[CONTAINER ID : 1632d24b635e] / # ps -ef PID   USER     TIME  COMMAND     1 root      0:00 sh     8 root      0:00 ps -ef / # ifconfig eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:04             inet addr:172.17.0.4  Bcast:172.17.255.255  Mask:255.255.0.0           UP BROADCAST RUNNING MULTICAST  MTU:65535  Metric:1           RX packets:10 errors:0 dropped:0 overruns:0 frame:0           TX packets:0 errors:0 dropped:0 overruns:0 carrier:0           collisions:0 txqueuelen:0           RX bytes:796 (796.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback             inet addr:127.0.0.1  Mask:255.0.0.0           UP LOOPBACK RUNNING  MTU:65536  Metric:1           RX packets:0 errors:0 dropped:0 overruns:0 frame:0           TX packets:0 errors:0 dropped:0 overruns:0 carrier:0           collisions:0 txqueuelen:1000           RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ # ls bin    dev    etc    home   lib    lib64  proc   root   sys    tmp    usr    var / # touch con1632d24b635e / # ls bin              dev              home             lib64            root             tmp              var con1632d24b635e  etc              lib              proc             sys              usr / #

03-26_Creating Docker Images**]**

  • 지금까지 다른 engineer가 만든 이미지를 사용했고, 우리가 원하는 이미지를 만들기 위해서는 Dockerfile을 만들어야 한다

    image

  • Dockerfile을 build하면 Docker Client가 Docker Server로 Dockerfile에 맞는 Image를 생성한다

    image

  • Dockerfile은 보통 다음과 같은 Flow로 작성한다

    image

03-27_BfDD**]**

03-28_Building a Dockerfile**]**

  • redis-server 를 만들어 보겠다

Specify a base image : Use an existing docker image as a base

FROM alpine

Run some commands to install additional programs : Download and install a dependency

RUN apk add --update redis

Specify a command to run on container startup : Tell the image what to do when it starts as a container

CMD ["redis-server"]

  • Dockerfile로 이미지 만들기

➜  redis-image sudo docker build . [+] Building 6.3s (7/7) FINISHED                                                                                         docker:desktop-linux => [internal] load build definition from Dockerfile                                                                                     0.0s => => transferring dockerfile: 358B                                                                                                     0.0s => [internal] load metadata for docker.io/library/alpine:latest                                                                         3.5s => [auth] library/alpine:pull token for registry-1.docker.io                                                                            0.0s => [internal] load .dockerignore                                                                                                        0.0s => => transferring context: 2B                                                                                                          0.0s => [1/2] FROM docker.io/library/alpine:latest@sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d                   0.0s => => resolve docker.io/library/alpine:latest@sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d                   0.0s => => sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d 1.85kB / 1.85kB                                           0.0s => => sha256:9cee2b382fe2412cd77d5d437d15a93da8de373813621f2e4d406e3df0cf0e7c 528B / 528B                                               0.0s => => sha256:c157a85ed455142fd79bff5dce951fd5f5b0d0c6e45e6f54cfd0c4e2bdec587b 1.49kB / 1.49kB                                           0.0s => [2/2] RUN apk add --update redis                                                                                                     2.7s => exporting to image                                                                                                                   0.0s => => exporting layers                                                                                                                  0.0s => => writing image sha256:f396f6ca44e6b28c049339480b6c532de62948335996eab74a715b3099f3d9f9                                             0.0s                                                                                                                                                View build details: docker-desktop://dashboard/build/desktop-linux/desktop-linux/swr131jc1gwyhtycv5bybvv6d                                    

Whats Next?   View a summary of image vulnerabilities and recommendations → docker scout quickview ➜  redis-image docker images REPOSITORY                                                                                     TAG       IMAGE ID       CREATED          SIZE <none>                                                                                         <none>    f396f6ca44e6   11 seconds ago   15.5MB ➜  redis-image docker run f396f6ca44e6 1:C 18 Sep 2024 15:05:01.471 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo 1:C 18 Sep 2024 15:05:01.471 * Redis version=7.2.5, bits=64, commit=00000000, modified=0, pid=1, just started 1:C 18 Sep 2024 15:05:01.471 # 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 18 Sep 2024 15:05:01.471 * monotonic clock: POSIX clock_gettime 1:M 18 Sep 2024 15:05:01.472 * Running mode=standalone, port=6379. 1:M 18 Sep 2024 15:05:01.472 * Server initialized 1:M 18 Sep 2024 15:05:01.472 * Ready to accept connections tcp

➜  .docker docker ps -a CONTAINER ID   IMAGE                                                                                          COMMAND                   CREATED          STATUS                        PORTS     NAMES 0f3709b6c900   f396f6ca44e6                                                                                   "redis-server"            23 seconds ago   Up 22 seconds                           zealous_allen ➜  .docker

03-29_Dockerfile Teardown**]**

  • Dockerfile을 분석해보자

    image

03-30_What's a Base Image?****]

  • dockerfile에서 base image는 software를 설치(구축) 및 실행하기 위한 환경이다

    image

    image

    image

03-31_The Build Process in Detail**]**

  • Dockerfile의 명령어 실행마다 이미지가 생성되고, 생성된 이미지에 다음 단계의 명령이 실행되어 새로운 이미지가 만들어진다

    image

03-32_A Brief Recap**]**

image

03-33_Rebuilds with Cache**]**

  • Dockerfile의 명령어 실행마다 이미지가 생성되고, 생성된 이미지 캐시에 저장되어 빌드시 여러번 이미지 생성하지 않고 재사용한다

    image

03-34_Tagging an Image**]**

  • custom 이미지에 tag를 달아 image 이름을 지정할 수 있다

  • Docker ID를 앞에 붙여, custom image 이름을 지정할 수 있고, Docker ID가 없다면 공식 public 이미지로 간주된다

    image

 

image

03-35_Quick Note for Windows Users**]**

03-36_Manual Image Generation with Docker Commit**]**

  • container로 image를 만들수 있다

  • container를 실행하고, container 내부에서 추가작업(RUN, 설치)를 한 후 image로 만들 수 있다

  • docker commit -c 'CMD ["~~~"]' <container id>

  • 새로운 이미지가 생성된다

    image

04-37_Project Outline**]**

  • 이번엔 NodeJS web app을 만들어 보자

  • 중간에 발생할 수 있는 오류를 수정하는 과정도 알아본다

    image

    image

04-38_Node Server Setup**]**

  • NodeJS Express 서버 세팅을 한다 (동일한 파일 경로에 아래 두 파일이 위치한다)
  • package.json

{     "dependencies": {         "express": "*"     },     "scripts": {         "start": "node index.js"     } }

  • index.js

const express = require('express');

const app = express();

app.get('/', (req, res) => {     res.send('Hi there'); });

app.listen(8080, () => {     console.log('Listening on port 8080'); })  

04-39_Reminder on Buildkit**]**

As mentioned earlier, Buildkit will hide away much of its progress which is something the legacy builder did not do. In the upcoming lectures will be discussing some output that will be quickly hidden by default. To see this output, you will want to pass the progress flag to the build command:

docker build --progress=plain .

Additionally, you can pass the no-cache flag to disable any caching:

docker build --no-cache --progress=plain .

Note - Do not try to use the no-cache flag with Lecture 47 Minimizing Cache Busting

Disabling Buildkit to match course output

To disable Buildkit, you can just pass the following variable to the build command:

DOCKER_BUILDKIT=0 docker build .