개발자의 길

[Infra] Docker (1) - Docker Engine

토아드 2024. 4. 14. 04:58
반응형

도커

도커 엔진

도커의 기본 단위는 '이미지'와 '컨테이너' 이다.

도커 이미지와 도커 컨테이너

도커 이미지는, 도커 컨테이너를 생성하기 위해 필요한 요소, 여러 계층으로 이루어진 바이너리 파일을 의미한다.
컨테이너를 실행시킬 때 해당 파일을 읽어서 실행시킨다.
이미지의 이름은.[저장소이름]:[이미지이름]:[태그] 로 구성된다. (alicek106/ubuntu:14.04) \

$ docker pull centos:7
# 이미지 받기
$ docker images
# 받은 이미지 확인

도커 컨테이너는 실행중인 가상 환경이라고 생각하면 된다. 도커 컨테이너는 프로세스 단위의 격리 환경을 만들기 때문에 성능 손실이 거의 없다. 또한 개발 시점에서 컨테이너에 서버 배포를 한다던가 하는 작업을 한 뒤 운영에 배포하기 위해서는 해당 컨테이너를 도커 이미지로 만들어서 운영 서버에 배포하면 그 이미지를 기반으로 컨테이너가 실행되기 때문에 개발/운영 환경의 차이로 인한 오류나 디버깅 과정 등을 대폭 줄일 수 있다.

$ docker -v
# 도커 버전 확인
$ docker create -t -t --name mycentos centos:7
# 도커 컨테이너 생성. 이미지 다운로드와 컨테이너 생성까지만을 실행한다.
# --name 명령어는 생성할 컨테이너의 이름을 설정
# create 명령어는 컨테이너를 생성만 하고 들어가진 않는다
# * 컨테이너는 생성될 때 실행할 명령어가 지정된다. 위와 같이 OS 같은 경우 /bin/bash 와 같이 쉘 명령어를 입려갈 수 있는 명령어가 실행된다    
$ docker start mycentos
# 도커 컨테이너 시작
$ docker attach mycentos
# 도커 컨테이너 내부로 들어가기
$ docker run -i -t ubuntu:14.04 
# 도커 컨테이너 실행. 이미지다운로드 ,도커 컨테이너 생성, 컨테이너 실행까지 일괄적으로 시킨다
# -i: 상호 입출력 활성화, -t: tty를 활성화해서 bash 셸을 사용하도록 설정
# 위 두개의 옵션을 이용해서 실행중인 $ docker 컨테이너에 접속하여 터미널상에서의 명령어 실행을 가능하게 한다. 
# ($ docker attach 를 실행한 것과 같은 동작을 하도록 한다)

$ docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=1234 -d  mysql:latest
# -p [호스트의포트]:[컨테이너의 포트] : 호스트의 포트를 컨테이너의 포트와 연결시키는 옵션
# -d : 컨테이너를 백그라운드에서 동작하도록 설정한다. 
# -e [환경변수명]=[환경변수값]: 환경변수 설정, 
$ docker ps 
# 지금까지 생성한 컨테이너 목록 확인
# -a 옵션으로 정지된 컨테이너도 포함하여 출력
$ docker rm angry_morse
# 컨테이너 삭제
# 실행중인 콘테이너는 삭제할 수 없습니다. 
# -f 명령어로 강제 종료가 가능합니다
$ docker stop angry_morse
# 컨테이너 중지
$ docker container prune
# 종료된 모든 컨테이너를 삭제하는 명령어
$ docker exec -i -t wordpressdb /bin/bash
# 컨테이너 내부에서 명령어를 실행한 뒤 그 결괏값을 반환받는다. 

도커 볼륨

도커 이미지로 컨테이너를 생성하면 컨테이너 레이어 내부에 컨테이너에서 쓰기한 데이터들이 저장되는데, 컨테이너를 종료하게 되면 이 데이터들을 모두 잃게 된다.
이러한 일을 막기 위해서는 컨테이너 외부의 볼륨 을 활용하는 방법이 있다. 컨테이너 외부의 볼륨을 연결하는 방법은 3가지가 있는데 아래와 같다.

  1. 호스트와 컨테이너가 볼륨을 공유하는 방법

도커엔진이 실행되는 호스트의 저장장소를 도커 컨테이너가 사용하는 형태이다. 아래와 같이 -v 옵션을 사용함으로써 공유가 가능하다

$ docker run -i -t -v --name my_volume_container /Users:/var/mydata ubuntu:latest
# 호스트나 도커 컨테이너에 해당 디렉터리가 존재하지 않을경우 생성한다
# 도커 컨테이너에 이미 존재하는 디렉터리가 있을 경우 호스트의 디렉터리로 덮어씌워진다(마운트된다)
  1. 볼륨 컨테이너를 생성하여 활용하는 방법

컨테이너를 생성할 때 --volumes-from 옵션을 사용하면 -v 옵션을 적용한 컨테이너의 볼륨 디렉터리를 공유할 수 있다.

$ docker run -t -t --name volumes_from_container --volumes_from my_volume_container ubuntu:latest
# 위에서 만든 my_volume_container 라는 녀석의 볼륨을 공유받는다

위와 같이 볼륨을 공유해주는 역할으로써만 동작하는 볼륨 컨테이너 를 실행해서 활용하는 것도 가능하다

  1. 도커엔진이 관리하는 볼륨을 생성하는 방법 (도커 볼륨)
    도커 볼륨은 호스트의 저장공간에 생성되긴 하지만, 사용자가 그것이 어디에 저장되고 관리되는지를 알지 못해도 된다는 장점이 있다.
$ docker volume create --name myvolume
# 도커 볼륨을 생성하는 명령어

$ docker run -it -v myvolume:/var/my$ dockervolume ubuntu:latest
# 위에서 생성한 도커 볼륨을 공유하도록 옵션을 줘서 실행
$ docker volume ls
# 생성된 도커 볼륨 리스트를 보여주는 명령어

$ docker inspect --type volume myvolume
[
    {
        "CreatedAt": "2024-04-04T15:52:20Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/$ docker/volumes/myvolume/_data",
        "Name": "myvolume",
        "Options": null,
        "Scope": "local"
    }
]
# 도커 구성단위의 정보를 확인하는 명령어. 위 명령어로 실제로 어디에 저장되는지 출력이 가능함

$ docker run -i -t --name volume_auto -v /root ubuntu:latest
# 자동으로 /root 라는 디렉터리에 볼륨을 자동으로 생성한다. 무작위 이름의 볼륨이 자동으로 생성됨

$ docker volume prune
# 불필요한 도커 볼륨들을 자동으로 삭제하는 명령어

컨테이너 로깅

컨테이너 내부에서 어떤 일이 일어나는지 알기 위해 로깅을 하는 것은 매우 중요하다. 도커는 stdout 과 stderr 로그를 별도의 메타데이터 파일로 저장하는데, 이를 확인하는 명령어 또한 제공한다

$ docekr run -d --name mysql -e MYSQL_ROOT_PASSWORD=1234 mysql:5.7
$ docker logs mysql 
# 해당 컨테이너의 로그를 확인하는 명령어
$ docker logs --tail 2 mysql
# --tail 2 : 로그 마지막 2줄만 출력하는 옵션
# -f : 로그를 실시간 스트림으로 확인 가능
# -t : 타임스탬프를 표시할 수도 있다
# --since : 유닉스 시간을 입력해서 해당 시간 이후의 로그를 확인 가능하다

위와 같은 컨테이너 로그는 JSON 형태로 도커 내부에 저장된다. 아래와 같은 위치에 저장되니 필요하다면 분석 해 볼 수도 있다.

/var/lib/docker/containers/${CONTAINER_ID}/${CONTAINER_ID}-json.log

$ docker run -it --log-opt max-size=10k --log-opt max-file=3 --name log-test ubuntu:latest
# --log-opt : 로그 저장 방식에대한 설정을 가능하다.

아무런 설정도 하지 않았다면 위에서 말한 것과 같이 JSON 으로 로그를 저장하지만, 다른 로깅 드라이버를 지정해주면 특정 포맷으로 저장도 해준다.
syslog, fluentd, aws cloudwatch 등으로 로그를 별도 서버에 적재할 수도 있다

컨테이너 자원 할당 제한

컨테이너는 별도 설정을 해 주지 않으면 호스트의 자원을 무한정으로 쓸수 있음으로, 컨테이너의 자원 할당량을 고려해서 호스트 내에서 실행되는 다른 컨테이너 간의 자원 문제로 인한 간섭이 없도록 하는게 좋다.

메모리 제한

$ docker run -d --memory=1g --memory-swap=3g ubuntu:latest
# --memory : 메모리 할당량을 주어진 용량으로 제한한다. 위 메모리를 초과하게 될 경우 컨테이너는 자동으로 종료된다.
# swap 메모리는 메모리의 2배로 설정되는데, --memory-swap 옵션으로 별도로 줄 수 있다

CPU 제한

$ docker run -d --cpu-shares 1024 ubuntu:latest
#--cpu-shares : 시스템의 CPU 를 얼마나 나눠서 쓸지를 명시하는 옵션. 1024 는 CPU 할당에서 1의 비중을 의미한다. 어디까지나 비중이지 1% 쓴다는 의미가 아니다.
#  만약 다른 컨테이너가 없다면 위 ubuntu 컨테이너는 100% 의 CPU 를 차지할 수 있다.

그 외에도 특정 CPU 사용 , CFS 주기, Block I/O 등을 제한 가능하다

도커 이미지

우리가 docker pull 이나 docker run 으로 이미지를 받는 명령어를 수행할 때, 이미지들은 기본적으로 도커 허브라는 공개된 저장소에서 가져온다. 도커 계정만 있다면 누구든지해당 공간에 이미지를 올리고 받을 수 있다

도커 이미지 생성

도커 이미지는 직접 만들 수도 있는데, 도커 컨테이너 안에서 작업한 내용을 이미지로 만드는 방법이 있다. 아래 커맨드를 이용하면 컨테이너에서 작업한 모든 것이 이미지로 저장된다

 docker commit [OPTIONS] <CONTAINER> <IMAGE_NAME> [REPOSITORY[:TAG]]
 # -a, --author : 작성자 정보를 입력합니다.
 # -m, --message: 이미지에 포함될 부가 설명합니다.
 # -p, --pause : 컨테이너를 일시 중지하고 커밋을 수행합니다.

위 커맨드를 이용해서 이미지를 만들면 현재 docker images 커맨드를 이용해서 생성된 이미지를 확인할 수 있다.

  docker rmi image_name:tag
  # 생성한 이미지를 삭제합니다. 이미지 이름만 삭제할 뿐, 레이어 파일을 삭제하지는 않습니다. 자세한 건 아래 도커 이미지 이해 참고.

도커 이미지 이해

도커 이미지는 여러 층의 '레이어' 라는 파일로 이루어져 있다. A 라는 이미지를 받아서 파일을 생성하는 등의 작업을 수행한 뒤 B 라는 이미지를 만들면 A 와 B 이미지가 개별적인 파일로 저장되는게 아니라, '레이어' 라는 파일을 공유하는 형태로 생성된다.
A 가 1 ~ 5 까자의 레이어로 이루어져 있다면, B 는 1 ~ 5 레이어 + 6 ~ 10 레이어 로 이루어진다.

위 상황에서 A 라는 이미지 삭제 커맨드를 실행하면 Untagged: ... 라는 출력 결과를 볼 수 있는데, 이는 이미지에 부여된 이름만 삭제한다는 것을 의미한다. B 이미지가 1 ~ 5 레이어를 사용하고 있기 때문이다. 이후 B 이미지를 제거한다면 Deleted: ... 라는 출력 결과를 볼 수 있다.

도커 이미지를 배포하기

도커 이미지를 만들었으면 배포하고 그것을 다른 서버에서 받을 수 있게 하는 작업이 필요한데, 이미지를 배포하는 방법은 크게 1. 도커 허브에 배포 하거나, 2. 도커 사설레지스트리에 배포 하는 두가지 방법이 있다. 여기서는 도커 허브에 배포하는 방법을 소개하고자 한다.

도커 허브에 배포하기

 docker tag image_name:tag new_image_name:tag
 # 같은 이미지를 가리키는 새로운 이름을 추가하는 커맨드입니다.

 docker login
 # 도커 허브 서버에 로그인하는 명령어입니다. 

 docker push new_image_name:tag
 # 도커 허브에 이미지를 올립니다

 docker pull new_image_name:tag 
 # 이제 도커 허브에 올라간 이미지를 받을 수 있습니다

큰 기업에서 자체 운영하는 사설 이미지 서버가 있는게 아니라면 보통 클라우드 서비스에서 제공하는 도커 이미지 저장소를 이용한다. AWS 로 예를 들면 ECR 이 있다.

Dockerfile

실제 서비스의 배포를 자동화 하는 경우 위와 같이 도커 컨테이너에 들어가서 작업한 내용을 commit 하는 방식은 구동한 컨테이너를 바로 배포하기 때문에 동작한다는 것을 보장할 수 있다는 점도 있는데, 배포 자동화에 사용하기는 적절치 않다.

그래서 도커는 Dockerfile 이라는 것을 제공해서 build 명령어를 작성한 다음 이를 빌드 함으로써 이미지로 만드는 것을 제공한다. build 명령어는 아래와 같다.

  • FROM : 생성할 이미지의 베이스가 될 이미지를 뜻한다
  • MAINTAINER : 이미지를 생성한 개발자의 정보를 나타낸다. (현재는 아래 LABEL 명령어로 대체하여 표현할 수 있으므로 사용되지 않는다)
  • LABEL : 이미지에 메타데이터를 추가합니다. 키:값 형태로 추가가 가능합니다
  • RUN : 이미지를 만들기 위해 컨테이너 내부에서 실행할 명령어를 구술합니다. 입력을 받아야 되는 명령이 있으면 build 시에 이를 오류로 간주한다는 점은 주의
  • ADD : 파일을 이미지에 추가합니다. 추가하는 파일은 Dockerfile 이 위치한 디렉터리인 Context 에서 가져옵니다.
  • WORKDIR : 명령어를 실행할 디렉터리를 나타냄 ( cd 와 같음 )
  • EXPOSE : Dockerfile 의 빌드로 생성된 이미지에서 노출할 포트를 설정합니다.
  • CMD: 컨테이너가 시작될 때마다 실행할 명령어를 설정합니다. Dockerfile 에서 단 한번만 사용할 수있다.
  • ENV : Dockerfile에서 사용될 환경변수를 지정합니다. (run 명령어 수행시의 -e 옵션과 같은 효과)
  • COPY : 로컬 디렉터리에서 읽어들인 컨텍스트로부터 이미지에 파일을 복사합니다.

위 명령어들을 이용해서 Dockerfile 을 작성하면 아래 명령어로 이미지를 빌드할 수 있습니다.

 docker build -t new_image_name:tag ./
 # -t : 생성될 이미지의 이름을 설정합니다. 지정하지 않으면 16진수 형태의 이름으로 이미지가 생성
 # build 명령어의 마지막에는 Dockerfile 이 저장된 경로를 지정
반응형