[Docker & Kubernetes] 2주차 정리
4.1. 도커 기초 개념
4.1.1. 도커 작동 방식
- Docker Client: 도커에 명령을 내릴 수 있는 CLI(Command Line Interface) 도구 -> container, image, volume 관리 가능
 - Docker Host: 도커를 설치한 server or VM -> 물리 서버가 될 수도 있고, 가상 서버가 될 수도 있음
 - Docker Registry: 도커 이미지를 저장하거나 배포하는 시스템 -> public/private으로 나눌 수 있음 - docker hub는 가장 유명한 public registry
 

- docker client에 명령어 입력 -> docker host의 docker daemon이 명령을 수신 -> docker host에 image가 존재하지 않는다면 docker registry에서 다운로드
 - docker daemon: docker와 관련된 resource를 관리하는 background process
 
4.1.2. Docker Image
- container 형태로 sortware를 배포하기 위해 필요한 모든 요소(코드, 라이브러리, 설정 등) -> 실행할 수 있는 포맷으로 compile 및 build한 package
 - docker image는 독립적 -> 의존성을 고려할 필요 X
 - 경량화된 package -> 비교적 작은 용량으로 제 역할 수행
 - 특정 시점의 docker container 상태를 담은 snapshot -> docker image를 통해 동일한 환경을 가진 여러 개의 container를 쉽게 생성 가능
 - multi layer 구조
 - docker hub와 같은 중앙 저장소에 저장되어 관리
 
4.1.3. Docker Container
- docker image를 실행할 수 있는 instance를 의미 -> docker image로부터 생성됨
 - 실행, 중지, 재실행, 삭제 등의 명령을 내릴 수 있음
 - 각 container는 독립적으로 실행 -> container는 자체적으로 file system를 가짐
 - container는 docker engine이 설치된 host OS를 이용 -> container 내부는 프로그램을 실행하기 위한 최소한의 binary, library로 구성됨
 
4.1.4. hello world 실행 과정

- docker - 도커 관련 명령어를 입력하겠다는 의미, run - container를 실행하겠다는 뜻, hello-world - container 이름
 
4.2. 도커 기초 명령어
4.2.1. Docker Image 다운로드
- docker image pull {이미지 이름:태그 이름} - docker daemon가 docker host에 image가 있는지 확인 후, 없을 경우 docker registry에서 해당 image 다운로드
 

- 태그명을 입력하지 않으면, 자동으로 latest 태그 적용
 - pull complete 메시지가 1개 -> ubuntu image는 한 개의 layer로 구성, hash 값은 docker image가 빌드될 때 생성된 ID
 - 다운로드한 모든 layer와 meta 정보를 포함하는 iamge의 hash 값 - 하나의 layer에 대한 ahsh값과는 다르다는 것을 확인
 - docker image pull [이미지 이름@DIGEST] - 해당 DIGEST의 image 다운로드 가능
 - latest 태그 -> ubuntu iamge를 다운로드했다는 상태 메시지 확인
 - 다운로드한 이미지의 URL
 

-> multi layer 구조의 image를 다운로드한 경우
4.2.2. Docker Image 상세 구조

- Image는 크게 Image Index, Image Manifest, Layer 세 가지 구조로 이뤄짐
 - image를 다운로드할 때 결과창에 출력되는 digest -> Image Index
 - image index는 다수의 Image Manifest로 구성됨
 - 각 image manifest는 다양한 OS 및 Architecture에서 해당 image를 활용할 수 있도록 설정값(config)과 다양한 Layer 제공
 
4.2.3. Docker Image 목록 확인
docker image ls

- REPOSITORY - 이미지 이름, TAG - 이미지 태그, iamge id(로컬에서 할당받은 IMAGE ID 값) - 다운로드한 이미지의 id(다운로드할 때 digest와 다름 -> docker registry에 존재하는 image의 digest 값), CREATED - 이미지가 만들어진 시간, SIZE - 이미지 크기
 
4.2.4. Docker Container 실행
docker container run [이미지명]
-> docker run 명령어는 도커 초기 버전에 활용한 명령어 -> 현재는 docker container run 명령어가 권장됨

4.2.5. Docker Container 목록 확인
docker container ls

- -a 옵션 - 실행/정지 상태인 container 모두 확인
 - 각 container는 CONTAINER ID를 가짐
 - Exited - container가 종료되었다는 뜻(숫자 0은 정상 종료를 의미)
 
4.2.6. Container 내부 접속

- -it 옵션 - 컨테이너 실행과 동시에 접속
 - interactive의 I - 표준 입력(STDIN)을 열어놓는다는 의미, tty의 T - 가상 터미널을 의미, IT -> 가상 터미널을 통해 키보드 입력을 표준 입력으로 container에 전달
 - username은 root, hostname은 container ID
 

-> 다른 터미널에서 ubuntu container 상태를 확인했을 때 status가 Up인 것을 확인 가능
- 컨테이너 내부에 접속해있는 터미널에서 exit 명령어 -> container 밖으로
 - 새롭게 실행한 terminal에서 docker container stop [컨테이너 ID] -> 실행 중인 컨테이너 종료
 

- docker container kill - 대기 없이 즉시 컨테이너 종료 -> 안정성 면에서 효율 X
 

-> 다시 container 실행 후 접속
4.2.7. Container 삭제

- docker container rm [컨테이너 ID] - 컨테이너 ID에 해당하는 container 삭제
 - docker rm -vf $(docker ps -aq) - container 모두 삭제
 
4.2.8. Image 삭제

- docker image rm [이미지 이름]
 - docker rmi -f $(docker images -aq) - image 모두 삭제
 
4.2.9. Docker Image 변경

-> container 내부 IP를 확인하려면 ifconfig 명령어 -> net-tools를 설치해야 함

-> 새 터미널을 열어서 net-tools를 설치한 container를 my-ubuntu라는 새로운 이름의 이미지로 저장
-> 0.1이라는 태그 추가

-> 기존 터미널에서 실행중인 container 종료 후, 새로 생긴 my-ubuntu image를 container로 실행 후 접속

-> my-ubuntu에는 net-tools가 설치되어 있으므로, ifconfig 명령어 사용 가능
4.2.10. Docker Image 명령어 모음
- docker image build - dockerfile로부터 이미지 빌드
 - docker image history - 이미지 히스토리 확인
 - docker image import - 파일 시스템 이미지 생성을 위한 tarball 콘텐츠를 import
 - docker image inspect - 이미지 정보를 표시
 - docker image load - tarball로 묶인 이미지를 로드
 - docker image ls - 이미지 목록을 확인
 - docker image prune - 사용하지 않는 이미지 삭제
 - docker image pull - 레지스트리로부터 이미지를 다운로드
 - docker image push - 레지스트리로 이미지를 업로드
 - docker image rm - 하나 이상의 이미지 삭제
 - docker image save - 이미지를 tarball로 저장
 - docker image tag - 이미지 태그를 생성
 
4.2.11. Docker Container 명령어 모음
- docker container create - 새로운 container를 생성하는 명령어
 - docker container start - create 명령어로 생성된 container를 실행
 - docker container run - create + start
 - docker attach - 실행 중인 container의 표준 입력(stdin), 표준 출력(stdout), 표준 오류(stderr) 스트림에 연결할 때 사용 -> 기존에 실행 중인 프로세스에 연결
 - docker exec - 실행 중인 container 내부에서 명령어를 실행하는 역할 -> 새로운 프로세스를 시작해서 container 내에서 작업을 수행
 
4.3. Docker Container Network
4.3.1. Docker Container Network 구조

-> my-ubuntu 접속 후 ifconfig

-> docker host의 네트워크 정보 확인

4.3.2. Docker Network 확인

- docker network ls - 도커 네트워크 확인, docker에서는 기본적으로 bridge, host, none이라는 세 가지 network driver 제공
 - bridge driver: 컨테이너를 생성할 때 제공하는 기본 드라이버. 각 컨테이너는 각자의 network interface를 가짐 -> 이는 docker host의 docker0와 바인딩 됨, --network=bridge 옵션으로도 사용 가능
 - host driver: 컨테이너를 생성할 때 컨테이너 자체적으로 network interface를 가지지 않고, host network interface를 공유, --network=host 옵션으로 사용 가능
 

-> host dirver를 사용하여 container 실행
-> network 정보가 host network 정보와 동일
- none driver: 실행한 container가 network interface 소유 X -> container 외부와의 통신 불가능, --network=none 옵션으로 사용 가능
 

-> none dirver를 활용하면 container 자체적으로 network interface 소유 X
4.3.3. Host에서 Container로 파일 전송


-> ex01 디렉토리에 test01.txt 파일 생성 후 텍스트 입력
-> cat - 해당 파일 내용 출력
-> pwd - 현재 위치
Vim: 비주얼 에디터(visual editor)라는 뜻에서 유래한 Vi의 개선된 버전인 Vi Improved를 의미하며, 키보드만 사용하는 text editor이다.
참고자료: https://ko.wikipedia.org/wiki/Vi
Vim 단축키
- 입력 모드 i
- 비주얼 모드 v
- 일반 모드 Esc
- ex 모드 :
- 저장 :w(새로운 파일일 경우 :w [파일명])
- 종료 :q
- 저장 후 종료 :wq
- 저장하지 않고 종료 :q!
- 덮어쓰기 :w!

- 새로운 터미널에서 ubuntu container를 새로 실행하고, 해당 container의 home directory에 test01.txt 파일 복사
 - docker container cp [출발 경로/보내고 싶은 파일명] [도착 컨테이너:파일 저장 경로] - 파일 복사 명령어
 

-> home directory에 정상적으로 복사됨
4.3.4. Container에서 Host로 파일 전송

-> ubuntu container에서 test01.txt 파일을 복사한 test02.txt 파일 생성
-> 해당 container 내부에는 docker가 설치되어 있지 않으므로 container 내부에서는 docker 명령어 실행 불가

-> container 외부에서 container/home에 있는 test02.txt 파일을 pwd 위치로 복사
4.4. Docker Storage
4.4.1. Docker Storage 개념
- Docker Container에서 생성되는 데이터를 보존하기 위해 사용됨
 

- bind mount: docker host directory를 직접 공유하는 방식
 - volume: docker를 활용해 volume을 생성 -> container의 directory와 공유하는 방식
 - tmpfs: docker host memory에 파일이 저장되는 방식 -> container를 삭제하면 파일도 함께 삭제
 
4.4.2. Docker Storage의 필요성
postgresql을 먼저 실행해보자.

-> docker hub에서 실행 방법 찾을 수 있음
- --name: 컨테이너 이름
 - -e: 환경 변수 설정 옵션
 - -d: 백그라운드 실행
 
sangyeong-park@bagsang-yeong-ui-MacBookPro ex01 % docker run --name some-postgres -e POSTGRES_PASSWORD=mysecretpassword -d postgres 
311e57797e1389ffa3ecc7daee92a2759e418b78c1a3d581d7af391c3ac6a589
sangyeong-park@bagsang-yeong-ui-MacBookPro ex01 % docker container ls
CONTAINER ID   IMAGE      COMMAND                   CREATED              STATUS              PORTS      NAMES
311e57797e13   postgres   "docker-entrypoint.s…"   About a minute ago   Up About a minute   5432/tcp   some-postgres
sangyeong-park@bagsang-yeong-ui-MacBookPro ex01 % docker container exec -it 311e57797e13 /bin/bash     
root@311e57797e13:/# psql -U postgres
psql (16.3 (Debian 16.3-1.pgdg120+1))
Type "help" for help.
postgres=# CREATE USER user01 PASSWORD '1234' SUPERUSER;
CREATE ROLE
postgres=# CREATE DATABASE test01 OWNER user01;
CREATE DATABASE
postgres=# \c test01 user01
You are now connected to database "test01" as user "user01".
test01=# CREATE TABLE table01(
test01(# id INTEGER PRIMARY KEY,
test01(# name VARCHAR(20)
test01(# );
CREATE TABLE
test01=# \dt
         List of relations
 Schema |  Name   | Type  | Owner  
--------+---------+-------+--------
 public | table01 | table | user01
(1 row)
test01=# SELECT * FROM table01;
 id | name 
----+------
(0 rows)
test01=# INSERT INTO table01 (id, name)
test01-# VALUES(
test01(# 1,
test01(# 'Sangyeong'
test01(# );
INSERT 0 1
test01=# SELECT * FROM table01;
 id |   name    
----+-----------
  1 | Sangyeong
(1 row)
test01=# \q
root@311e57797e13:/# exit
exit
-> Database에 접속하여 table을 생성
sangyeong-park@bagsang-yeong-ui-MacBookPro ex01 % docker container ls
CONTAINER ID   IMAGE      COMMAND                   CREATED         STATUS         PORTS      NAMES
311e57797e13   postgres   "docker-entrypoint.s…"   6 minutes ago   Up 6 minutes   5432/tcp   some-postgres
sangyeong-park@bagsang-yeong-ui-MacBookPro ex01 % docker container stop 311e57797e13
311e57797e13
sangyeong-park@bagsang-yeong-ui-MacBookPro ex01 % docker container ls
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
sangyeong-park@bagsang-yeong-ui-MacBookPro ex01 % docker container ls -a
CONTAINER ID   IMAGE           COMMAND                   CREATED          STATUS                        PORTS     NAMES
311e57797e13   postgres        "docker-entrypoint.s…"   7 minutes ago    Exited (0) 10 seconds ago               some-postgres
eb438d4d8ec0   ubuntu          "/bin/bash"               24 minutes ago   Exited (0) 13 minutes ago               condescending_robinson
16b8330a6b09   my-ubuntu:0.1   "/bin/bash"               39 minutes ago   Exited (0) 37 minutes ago               xenodochial_shtern
1bb21c09aa1c   my-ubuntu:0.1   "/bin/bash"               41 minutes ago   Exited (127) 39 minutes ago             kind_darwin
2137e4462ff0   my-ubuntu:0.1   "/bin/bash"               2 hours ago      Exited (0) 45 minutes ago               elegant_blackburn
sangyeong-park@bagsang-yeong-ui-MacBookPro ex01 % docker container start 311e57797e13
311e57797e13
sangyeong-park@bagsang-yeong-ui-MacBookPro ex01 % docker container ls
CONTAINER ID   IMAGE      COMMAND                   CREATED         STATUS          PORTS      NAMES
311e57797e13   postgres   "docker-entrypoint.s…"   7 minutes ago   Up 12 seconds   5432/tcp   some-postgres
sangyeong-park@bagsang-yeong-ui-MacBookPro ex01 % docker container exec -it 311e57797e13 /bin/bash                                              root@311e57797e13:/# psql -U postgres
psql (16.3 (Debian 16.3-1.pgdg120+1))
Type "help" for help.
postgres=# \c test01 user01
You are now connected to database "test01" as user "user01".
test01=# \dt
         List of relations
 Schema |  Name   | Type  | Owner  
--------+---------+-------+--------
 public | table01 | table | user01
(1 row)
test01=# SELECT * FROM table01;
 id |   name    
----+-----------
  1 | Sangyeong
(1 row)
test01=# \q
root@311e57797e13:/# exit
exit
sangyeong-park@bagsang-yeong-ui-MacBookPro ex01 %
-> container를 정지시켰다 다시 실행해도 생성했던 테이블이 유지됨
postgres=# \c test01 user01
connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL:  role "user01" does not exist
Previous connection kept
postgres=# 
postgres=# \q
root@c2c8fc2418c3:/# exit
exit
-> container를 삭제 후 재실행했을 때는 기존의 데이터가 같이 삭제된 모습
4.4.3. Volume

- docker volume ls - 도커 볼륨 리스트 확인
 - docker volume create [도커 볼륨명] - 도커 볼륨 생성
 

-> docker volume인 myvolume01과 연동시켜 PostgreSQL container 실행
- --mount 옵션 활용 -> source=[도커볼륨명], target=[컨테이너 내부 경로]
 - 명령어 중 ','를 사용할 때 띄어쓰기 X
 - myvolume01 볼륨과 container 내부의 /var/lib/postgresql/data 경로 연결
 
postgres=# CREATE USER user01 PASSWORD '1234' SUPERUSER;
CREATE ROLE
postgres=# \du
                             List of roles
 Role name |                         Attributes                         
-----------+------------------------------------------------------------
 postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS
 user01    | Superuser
postgres=# \q
root@5982bb922445:/# cd /var/lib/postgresql/data/
root@5982bb922445:/var/lib/postgresql/data# ls
base	      pg_hba.conf    pg_notify	   pg_stat	pg_twophase  postgresql.auto.conf
global	      pg_ident.conf  pg_replslot   pg_stat_tmp	PG_VERSION   postgresql.conf
pg_commit_ts  pg_logical     pg_serial	   pg_subtrans	pg_wal	     postmaster.opts
pg_dynshmem   pg_multixact   pg_snapshots  pg_tblspc	pg_xact      postmaster.pid
root@5982bb922445:/var/lib/postgresql/data# exit
exit
-> volume과 연결된 경로에 정보 저장

-> container 삭제 후 다시 실행
- -v - 볼륨과 연결하여 실행할 때, --mount 옵션 뿐만 아니라 -v or -volume 옵션도 사용 가능
 
sangyeong-park@bagsang-yeong-ui-MacBookPro ~ % docker exec -it 3347c965694e /bin/bash
root@3347c965694e:/# psql -U postgres
psql (16.3 (Debian 16.3-1.pgdg120+1))
Type "help" for help.
postgres=# \du
                             List of roles
 Role name |                         Attributes                         
-----------+------------------------------------------------------------
 postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS
 user01    | Superuser
postgres=# \q
root@3347c965694e:/# exit
-> 삭제했다 다시 실행해도 데이터 유지
sangyeong-park@bagsang-yeong-ui-MacBookPro ~ % docker volume inspect myvolume01
[
    {
        "CreatedAt": "2024-07-29T21:00:31+02:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/myvolume01/_data",
        "Name": "myvolume01",
        "Options": null,
        "Scope": "local"
    }
]
- inspect - 볼륨 정보 확인
 - mountpoint - 컨테이너의 데이터를 보관하는 로컬 호스트 경로 -> myvolume01이라는 볼륨에서 관리하는 데이터가 존재하는 경로는/var/lib/docker/volumes/myvolume01/_data라는 뜻
 
4.4.4. bind mount
sangyeong-park@bagsang-yeong-ui-MacBookPro ex01 % pwd
/Users/sangyeong_park/ce/study/DockerKuber/work/ch04/ex01
sangyeong-park@bagsang-yeong-ui-MacBookPro ex01 % docker container run -e POSTGRES_PASSWORD=mysecretpassword --mount type=bind,source=/Users/sangyeong_park/ce/study/DockerKuber/work/ch04/ex01,target=/work -d postgres
65cb52fd35954866f51c6854486bcf4832f2f803a80a063d59d47bded6beb8fa
-> --mount 옵션으로 docker host의 pwd 경로와 docker container 내부의 /work 경로 연결

-> container 내부의 /work 경로에 정상적으로 연결됨

-> docker container 내부에 test_dir을 생성해도 host directory에도 동일함
-> 삭제도 마찬가지로 연동됨
4.4.5. tmpfs mount
sangyeong-park@bagsang-yeong-ui-MacBookPro ex01 % docker container run \
> -e POSTGRES_PASSWORD=mysecretpassword \
> --mount type=tmpfs,destination=/var/lib/postgresql/data \
> -d postgres
e43bc98e6c9d04be76717ac991aef85f11e29f5beaaa23a3539a52a1bf844ceb
-> tmpfs 연결하여 실행
docker container ls
CONTAINER ID   IMAGE      COMMAND                   CREATED          STATUS          PORTS      NAMES
e43bc98e6c9d   postgres   "docker-entrypoint.s…"   40 seconds ago   Up 38 seconds   5432/tcp   objective_poitras
docker inspect objective_poitras --format ''
참고자료
- "한 권으로 배우는 도커 & 쿠버네티스", 장철원, 한빛미디어, 2024.04.29
 - https://nolboo.kim/blog/2016/11/15/vim-for-beginner/
 
완전 초보를 위한 Vim <!--- @n0lb00's Blog-->
Vim은 Emacs와 함께 어렵기로 소문난(?) 에디터이다. 얼마나 어려운지 나가는 것을 몰라서 2년간 계속 사용하고 있다는 풍자 트윗을 @iamdevloper이 올리자 수천 명이 리트윗하기도 했다. 나도 처음 Vim
nolboo.kim