dangtong76 blog cloudrain21 blog


1. Docker Container

1.1. Container & Virtualization

하드웨어 성능이 올라가면서, 유휴자원을 활용하는 가상화(자원을 나눠서 사용) 기술이 대두됨

가상화 종류

1.2. Docker Architecture

image

Docker’s strengths

Docker’s main function

컨테이너 간 간섭을 방지하기 위해 Isolation 기술 (리눅스 namespace와 cgroup 기능) 사용

1.3. Technique for Docker

OverlayFS

이전의 unionFS 계열로 aufs overlayFS가 뒤를 이음 (현재는 overlayFS2)
여러 이미지 레이어에 있는 파일과 디렉토리를 Runtime layer에 함께 Mount하는 Union Mount 기술 사용
기본 컨테이너 이미지에 추가 작업 시 COW(Copy on Write)[^1] 방식으로 생성
[^1]: 부모 프로세스가 자식 프로세스를 생성할 때 전부 복제하지 않고, 쓰기가 발생했을 때 변경된 부분만 복제하는 방법과 유사
도커 이미지관리에 사용되는 FS or Library : Btrfs, AUFS, Device Mapper, OverlayFS

Linux Kernel - Namespace

독립적인 공간을 제공하고 서로가 충돌하지 않도록 하는 기능
mnt(파일시스템 마운트),pid(프로세스),net(네트워크),ipc(SystemV IPC),uts(hostsname),user 모두 독립적으로 할당

namespace 테스트

unshare --fork --pid -- mount-proc bash
ps --aux
top
exit

Linux Kernel - Cgroups

Control Groups는 Resource에 대한 제어를 가능하게 함
Process 또는 Thread를 그룹화 하여 관리 (Memory, CPU, I/O, network, device node 그룹별로 제한 가능)

Linux Kernel - 가상 Bridge와 가상 NIC(Network Interface Card)

가상 NIC
컨테이너 별 각각의 가상 NIC가 할당(ContainerA - eth0, ContainerB - eth0)
가상 NIC는 docker0(172.17.0.0/16)라는 가상 bridge로 연결되어 컨테이너끼리 또는 호스트(물리NIC)를 통해 외부 네트워크로 연결 (Host - eth0)



2. Managing Docker Container

2.1. Installing Docker Engine

도커 패키지 리포지토리 연결 및 설치

# yum install -y yum-utils # 필요 util 설치
# yum-config-manager --add-rep https://download.docker.com/linux/centos/docker-ce.repo # 도커 구성 매니저 설치
# yum repolist
# yum -y install docker-ce docker-ce-cli containerd.io # 도커 설치
# yum list docker-ce
# systemctl start docker.service # 서비스 시작
# systemctl enable docker.service 
# systemctl is-active docker.service
# docker --help

2.2. Docker container image

도커 이미지 관리

# docker search --help 
# docker search centos -s 1000  # repository에서 centos 검색
# docker pull --help
# docker pull centos  # repository에서 centos 가져오기
# docker images
# docker tag --help
# docker tag centos:latest centos:ver7  # centos 태그 latest->ver7로 변경
# docker rmi --help
# docker rmi centos # centos image 제거
# docker image prune # 이름없는 dangling 이미지 제거
# docker login
# docker tag centos:latest nueees/repo-web:centos
# docker push --help
# docker push nueees/repo-web:centos

2.3. Docker container management

도커 컨데이너 관리

# docker create --help
# docker create -it --name c1 centos # centos 이미지로 c1라는 컨테이너 생성
# docker ps --help
# docker ps -a
# docker inspect --help
# docker inspect c1 # 
# docker start --help
# docker start c1
# docker stop --help
# docker stop c1
# docker run --help
# docker run -it --name c2 centos
# docker run -d --name web1 httpd
# docker rm -f web1

docker run: (create+start)
docker exit: 컨테이너 종료
Ctrl+P+Q: 컨테이너 종료하지 않고 빠져나옴 docker exec -it [container_name] /bin/bash: 외부에서 컨테이너 진입 시 사용되며 container에 exec를 사용해서 실행되는 명령어는 pid 1이 살아있을 때만 실행되고 container가 재시작 될때는 같이 재시작 되지 않음
docker attach [container_name]: exec와 달리 웹서버같이 백그라운드에서 실행되는 container에서는 커맨드는 입력할 수 없고 로그만 볼 수 있음

exec는 container에서 새로운 프로세스를 실행시킬 때 사용한다. container에 bin/bash를 실행시켜서 쉘을 띄우는데도 사용한다. exec를 사용해서 실행되는 명령어는 pid 1이 살아있을 때만 실행되고 container가 재시작 될때는 같이 재시작 되지 않는다.

그리고 만약 container가 pause되면 docker exec 명령어는 에러를 내고 실행실패된다.

# docker attach --help
# docker run -itd --name c1 centos 
# docker attach c1  # background에 실행중인 c1 컨데이너 접근
# docker exec --help
# docker run -d --name web1 httpd
# docker exec -it web1 bash  # web1 컨테이너 접근해서 bash 실행
# docker top --help
# docker top web1  # web1 컨테이너에서 실행중인 process 확인
# docker top web1 aux 
# docker rename --help
# docker rename c1 newc1
# docker pause --help
# docker pause web1
# docker unpaues web1
# docker cp --help

# docker run -itd --name c1 centos
# docker cp dockercp.txt c1:/ # host file -> container c1의 /경로로 copy
# docker exec -it c1 cat /dockercp.txt

# docker diff --help
# docker attach c1
## rm -f anaconda-post.log # 기존 컨테이너 내 log 삭제 후
# docker diff c1

# docker commit --help
# docker commit c1 centos:hello # 기존 c1 container로 new image 생성
# docker images

# docker save --help # 여러개 이미지를 archive file로 저장 시
# docker save -o imgarc.tar centos:hello httpd:latest # centos:hello, httpd 두개 image를 archive file로 저장

# docker load --help
# docker load -i imgarc.tar # archive file에 저장된 이미지 불러오기
# docker images # 불러온 이미지 확인

# docker export --help # 컨테이너 파일시스템을 archive file로 추출
# docker attach c1
## echo "This is export test" > export.txt
# docker export -o testexport.tar c1
# tar tf testexport.tar | grep export.txt

# docker import --help # export로 컨테이너로 추출한 archive file로 이미지로 생성
# docker import testexport.tar export:test

컨테이너 네트워크 구성

# ip a s
# brctl show
# docker run -itd --name c1 centos
# brctl show
# docker attach c1
## yum -y install net-tools
## ifconfig
## rount -n # docker0는 172.17.0.0/16 네트워크 사용하고 외부 통신 가능
## ping -c2 google.co.kr
# iptables -L -t nat # 게이트웨이 172.17.0.1이며 마스커레이딩 설정 됨

# docker network --help
# docker network ls # 도커 네트워크는 bridge, host, none 세가지

# docker inspect bridge
# docker network create --help
# docker network create d-net # bridge 유형으로 도커 네트워크 생성
# docker inspect d-net # 네트워크 범위(subnet) 자동으로 172.18.0.0/16으로 설정
# docker network create --subnet 192.168.0.0/24 --gateway 192.168.0.254 custom-net
# docker run -it --net custom-net --name a1 alpine # 사용자 정의 custom-net 네트워크 사용하여 컨테이너 생성

# docker run -it --net host --name a2 alpine # host 유형으로 생성시 host 네트워크를 공유
## ifconfig

# docker run -it --net none --name a3 none alpine # none 유형은 네트워크 할당 안함
## ifconfig

컨테이너 통신

# docker run -itd --name a1 alpine
# docker run -itd --name a2 --link a1 alpine
# docker attach a2
## ping a1 # ping 감
# docker attach a1
## ping a2 # ping 가지 않음
# docker exec a1 cat /etc/hosts
# docker exec a2 cat /etc/hosts # a1이 등록된 걸 확인

# docker run -itd --name a3 --link a1:alpine1 alpine # 별칭으로 링크 등록
# docker exec a1 ping alpine1 # ping 감
# docker exec a3 cat /etc/hosts # a1과 alpine1으로 등록된 걸 확인

# docker run -d --name web1 httpd
# curl localhost # container에서는 80포트가 열려있으나 실제 host의 주소로 접근 불가
# docker run -d -p 80:80 --name web2 httpd # host의 port 80으로 요청오면 container 80으로 전달 (호스트:컨테이너)

호스트의 특정 포트가 컨테이너 포트와 연결되어 있으면 해당 포트는 다른 컨테이너와 연결될 수 없음.

컨테이너 볼륨

# mkdir volume
# echo hello > volume/hello.txt
# docker run -it -v /boot/volume:/mnt --name v1 centos # host 디렉토리를 container와 공유 (호스트:컨테이너)
## ls /mnt
## cat /mnt/hello.txt
## df -h # /mnt 디렉토리가 host의 /dev/sda1에 연결되어 있음

# mkdir vol1 vol2 vol3
# docker run -it -v /boot/vol1:/vol1 \
 -v /boot/vol1:/vol1  -v /boot/vol1:/vol1 --name v2 centos # 동시에 다수 볼륨도 연결가능

# docker run -it -v /boot/vol1:/vol1 --name c2 centos # 하나 볼륨을 동시에 Read-Write시 crash 발생
# docker run -it -v /boot/vol1:/vol1:ro --name c3 centos # 볼륨 공유시엔 하나 외 나머지는 Read-Only로
## touch /vol1/xxx

# docker run -it -v vol-1:/vol1 --name c1 centos # host에서 디렉토리 생성없이 docker volume 생성 후 연결 (도커볼륨:컨테이너)
## touch /vol1/x
# docker run -it -v vol-1:/vol1 --name c2 centos 
## ls /vol1 # 파일 x 확인 가능
# docker volume ls # docker 볼륨 확인
# docker inspect vol-1 # 실제로는 host 디렉토리 사용

# docker volume create --help
# docker volume create vol2 # 수동으로도 생성 가능

# docker run -it --name m1 mysql
# docker inspect m1 # 도커 볼륨을 자동으로 생성하는 이미지가 있음 ("Volumes":{...)
# docker volume ls # 생성된 볼륨 확인

** 변수 사용해서 생성 ** 컨테이너에만 만들어 줌 /usr/src/app/node_modules 기존에 로컬 폴더에 있는거 옮김 /usr/src/app

# docker run -p 5000:8080 -v /usr/src/app/node_modules -v ${pwd}:/usr/src/app  nueees/nodejs:latest # mac용
# docker run -p 5000:8080 -v /usr/src/app/node_modules -v %cd%:/usr/src/app  nueees/nodejs:latest # window용
# docker exec 6e76b8fd3085 ls -lrt /usr/src/app
total 4
-rwxrwxrwx   1 root root  285 Apr 14 10:19 package.json
-rwxrwxrwx   1 root root  265 Apr 14 10:23 server.js
-rwxrwxrwx   1 root root  121 Apr 14 11:37 Dockerfile
drwxr-xr-x 155 root root 4096 Apr 14 11:50 node_modules

컨테이너 환경변수 설정

# docker run -it -e a=100 --name c1 centos
## echo $a

# docker run -it --name db1 mysql # error 출력되며 env 설정 필요
# docker ps -a
# docker inspect db1 # ("Entrypoint":[...)
# docker run -d -e MYSQL_ROOT_PASSWORD=1234 --name db2 mysql # 환경변수 주고 실행

보통 inpsect 내 “Cmd”:[“mysql”]가 실행되나,
Entrypoint가 지정되어 있으면 “Entrypoint”:[“docker-entrypoint.sh”]이 우선 실행됨

컨데이너 로그 확인

# docker logs --help
# docker logs db1 # 위 환경변수 오류 error log 확인 가능
# docker logs --tail 2 db2 
# docker logs --since "2021-10-12T01:00" db2

컨테이너 자원 할당

# docker run -d --name web1 httpd # options 없이 자원 할당
# docker stats web1 # 최대치 할당
# docker run -d --name web2 --memory="200m" httpd 
# docker stats --no-stream web1 # 메모리 limit 200MB
# 

# docker update --help
# docker update --memory=500m web2 # up가능하나 down은 불가

# docker run -itd -c 10 --name a1 alpine # 가중치 1로 할당
# docker run -itd -c 20 --name a2 alpine # 가중치 2로 할당
# docker attach a1
## dd if=/dev/zero of=/dev/null &
# docker attach a2
## dd if=/dev/zero of=/dev/null &
# docker stats # cpu 사용률 a2가 a1의 두배 확인

# docker run -itd --name a3 -cpus="0,2" alpine
## dd if=/dev/zero of=/dev/null &
# docker stats # a3의 cpu 사용률 20% 확인

# docker run -itd --name c1 --devie-write-bps /dev/sda:1mb centos # sda 디스크에 write작업시 속도 limit을 1MB/s
# docker attach c1
## dd if=/dev/zero of=/perftest bs=1M count=10 oflag=direct
# docker run -itd --name c2 centos # 제한없이 
# docker attach c2
## dd if=/dev/zero of=/perftest bs=1M count=10 oflag=direct

CPU, Memory, Block 제한은 가능하나 NET I/O는 제한 불가

워드프레스 컨테이너 실행 example

# docker network create wp-web # 네트워크 생성
# docker run -d --name wp-db \ 
    --net wp-net \
    -v wp-db-vol:/var/lib/mysql \
    -e MYSQL_ROOT_PASSWORD=1234 \
    -e MYSQL_DATABASE=wordpress \
    -e MYSQL_USER=wordpress \
    -e MYSQL_PASSWORD=1234 \
    mysql:5.7    
# docker run -d --name wp-web \
    --net wp-net \
    -v wp-web-vol:/var/www/html \
    --link wp-db:mysql \
    -e WORDPRESS_DB_HOST=wp-db:3306 \
    -e WORDPRESS_DB_PASSWORD=1234 \
    -p 80:80 \
    wordpress

http://localhost:8080 또는
http://localhost:8080/wp-admin/install.php로 확인



3. Building Docker Image

3.1. Dockerfile

# docker run -it --name c1 centos
# yum -y install httpd > /dev/null 
## systemctl start httpd
## systemctl enable httpd # httpd 이미지는 CentoOS와 호환되지 않아 설치 시 오류 발생

# docker inspect centos # container boot시 명령어가 지정되어 있음 ( "Cmd": ["/bin/sh", "-c", "#(nop)", "CMD [\"/bin/bash\"]"...)
# dodker inspect httpd # ( "Cmd": ["/bin/sh", "-c", "#(nop)", "CMD [\"httpd-foreground\"]"...)

이 경우 직접 컨테이너를 구동하고 수정하는 방식으로는 특정 어플리케이션 지정할 수 없음
Dockerfile을 사용해야 함

Dockerfile 생성

# mkdir dftest1
# cd dftest1
# vi Dockerfile
FROM httpd:latest
MAINTAINER nueees
RUN yum -y install httpd
COPY index.html /var/www/html
CMD /usr/sbin/httpd -D FORGROUND
# docker build -t test:1.0 . # 현재 디렉토리(.)로 빌드
# docker images # test:1.0으로 추가된 것 확인
  1. base image (베이스 이미지)
  2. command (실행 명령)
  3. env (환경 변수)
  4. run (실행 데몬)
명령어 설명
FROM 베이스 이미지 지정
MAINTAINER 작성자 지정
RUN 명령어 실행
CMD 데몬 실행
LABEL 라벨 지정
EXPOSE 포트 내보내기
ENV 환경변수 설정
ADD 파일 추가
COPY 파일 복사
VOLUME 볼륨 마운트
ENTRYPOINT 데몬실행
USER 사용자 설정
WORKDIR 작업 디렉토리 설정
ONBUILD build 후 실행 명령

3.2. Docker image build

# docker build -help
# cat /root/file/Dockerfile
# docker build -t base:1.0 /root/file/
# docker images

docker layer 구조

# docker build -t base:1.0 /root/file # 실행시 레이어 구조가 하나씩 나옴
  1. setp 1/5 : FROM centos
  2. step 2/5 : MAINTAINER nueees
  3. step 3/5 RUN yum -y install httpd
  4. step 4/5 COPY index.html /var/www/html
  5. step 5/5 CMD /usr/sbin/httpd -D FORGROUND



4. Docker Image Registry

4.1. Registry - Docker Image Registry

도커 허브에 공개되어 있는 registry 공식 이미지

# docker search registry
# docker pull registry:2.0
# docker images
# docker run -d -p 5000:5000 --name regTest registry:2.0

# docker tag httpd localhost:5000/regTest
# docker push localhost:5000/regTest # upload
# docker rmi localhost:5000/regTest
# docker pull localhost:5000/regTest # download
# docker images

4.2. Harbor - Docker Image Registry

one of private registries
web 기반, 다양한 기능 제공

Harbor 설치 파일 download

# wget "https://github.com/goharbor/harbor/releases/download/v2.3.3/harbor-offline-installer-v2.3.3.tgz"
# tar xzvf harbor-offline-installer-version.tgz

HTTPS 구성 후

Configuration File(YML File) 수정

# vi harbor.yml
5  hostname: docker.nueees.co.kr
13 https: 
15 port: 443
17 cerificate: 
18 private_key: 

Harbor 설치

# systemctl restart docker
# ./install.sh

Harbor 사용

# docker login -u admin -p Harbor12345 192.168.56.101
# docker tag centos:latest 192.168.56.101/library/docker:centos
# docker push 192.168.56.101/library/docker:centos
# docker rmi 192.168.56.101/library/docker:centos
# docker pull 192.168.56.101/library/docker:centos

웹에서 Harbor IP 접속하여 대시보드 확인