Docker

박상훈·2022년 5월 12일
0
post-thumbnail

컨테이너 관리 도구

유닉스, 리눅스

하나의 운영체제 안에서 자원을 분리해 할당하고 실행 되는 프로세스를 격리하여 관리하며
파일 시스템 설정 및 자원 공간 관리를 직접 수행

도커

유닉스, 리눅스와 같은 복잡한 과정을 명령어 입력으로 쉽게 만들어 주는 도구
도커를 사용하면 컨테이너를 생성할 때 개별적인 실행 환경 분리와 자원 할당을
개발자가 설정하지 않아도 도커가 알아서 해결해준다

사용법


docker search nginx

NAME DESCRIPTION STARS OFFICAIL AUTOMATED
...

NAME : 이미지가 저장된 레지스트리 이름
DESCRIPTION : 이미지 설명
STARTS : 이미지를 내려받은 사용자의 평가 수
OFFICIAL [OK] : 공식 업체에서 제공하는 이미지
AUTOMATED [OK] : 도커 허브에서 자체적으로 제공하는 이미지 빌드 자동화 기능으로 생성한 이미지

docker pull nginx

태그 : 버전을 명시하지 않으면 latest 태그 적용, 가장 최신 버전
레이어 : 하나의 이미지는 여러개의 레이어로 구성되어 있음
다이제스트 : 이미지의 고유 식별자로 해시 함수로 생성되어 이미지 동일 검증에 사용
상태 : 내려받은 이미지에 대한 상태

Using default tag: latest
영문 + 숫자 문자열 레이어: Pull complete
Digest: sha256:9ewjrgi09g ...
status: Downloaded newer image for docker.io/nginx:latest

이미지 태그 : 이름이 동일한 이미지에 추가하는 식별자, 버전 또는 플랫폼(OS 등...) 구분
이미지 레이어 : 압축 파일과 다르게 레이어를 이용하면서 동일한 레이어가 있는 경우 새로 받지 않고 재사용하여 디스크를 효율적으로 사용 가능

docker run -d --restart always nginx
16진수 문자열 생성 : 컨테이너 식별 ID

-d(--detach) : 컨테이너를 백그라운드에서 구동, 지속적으로 작동해야하는 프로그램에 사용
--restart always : 컨테이너 재시작과 관련된 정책을 의미하는 옵션, 가상 머신을 중지 후 다시 실행해도 자동으로 컨테이너가 기존 상태를 이어감

값			컨테이너 비정상 종료 시	도커 서비스 시작 시
no(default)		재시작 안함			시작하지 않음
on-failure		재시작				 시작
always			재시작				 시작
unless-stopped  재시작				사용자가 직접 정지하지 않은 컨테이너 시작

docker ps

옵션으로 -f(--filter) key=value 를 입력하여 검색 결과를 필터링 할 수 있다

CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
eecee26f38db   nginx     "/docker-entrypoint.…"   10 minutes ago   Up 10 minutes   80/tcp    keen_poincare

ps : process status, 프로세서 상태
CONTAINER ID : 컨테이너 식별 ID
IMAGE : 컨테이너를 만드는 데 사용한 이미지
COMMAND : 컨테이너가 생성될 때 내부에서 작동할 프로그램을 실행하는 명령어
CREATE : 컨테이너 생성 시각
STATUS : 컨테이너 작동 시각, 컨테이너 재실행 시 초기화
PORTS : 컨테이너가 사용하는 포트와 프로토콜
NAMES : 컨테이너 이름, 직접 명시 가능

docker run -d -p 8080:80 --name [container name] --restart always nginx

-p(--publish) : 외부에서 호스트로 보낸 요청을 컨테이너 내부로 전달하는 옵션
8080:80 : <요청 받을 호스트 포트> : <연결할 컨테이너 포트>

컨테이너 내부 파일 변경


컨테이너 내부에서 컨테이너 외부의 파일을 사용하는 방법 4가지

docker cp [host path][container name]:[container inner path]
호스트에 위치한 파일을 구동 중인 컨테이너 내부에 복사
컨테이너에 임시로 필요한 파일을 단편적으로 전송하거나 컨테이너에 있는 내용을 추출할 때 사용

Dockerfile ADD
Dockerfile 에 ADD 라는 구문으로 파일을 지정하면 이미지 빌드 시 이미지 내부로 복사
사용자가 원하는 파일을 선택해 사용할 수 없음

바인드 마운트
호스트와 컨테이너 내부를 연결해 동시 반영하는 방법
데이터 베이스 데이터 디렉토리, 서버 첨부파일 디렉토리에 적합

볼륨
쿠버네티스 볼륨 구조와 유사
NFS 같은 공유 디렉토리를 생성하여 다른 호스트에서도 도커가 관리하는 볼륨을 함께 사용

바인드 마운트로 호스트, 컨테이너 연결하기

바인드 마운트로 연결할 때 호스트에 폴더가 컨테이너의 폴더를 덮어쓴다
마운트 되지 않고 컨테이너에 직접적으로 생성한 파일은 삭제되니 주의해서 사용해야 한다

호스트에 폴더를 생성한 후

docker run -d -p [host port]:[container port] -v [host folder path]:[container folder ptah]
--restart always --name [container name][image name]

-v(--volume) : 호스트 디렉토리, 컨테이너 디렉토리 연결하는 옵션

컨테이너 내부 확인하는 방법

docker exec <컨테이너 ID | 이름> ls <컨테이너 폴더>

볼륨으로 호스트, 컨테이너 연결하기

볼륨 생성

docker volume create [volume name]

볼륨 조회

docker volume inspect [volume name]

Mountpoint path 를 확인하고 바인드 마운트로 실행했던 docker run 에서 host folder path 에
Mountpoint path 를 넣어주면 된다

바인드 마운트와 차이점으로 폴더를 강제 덮어쓰지 않고 서로 동기화 시키는 구조이기 때문에
컨테이너 폴더에 파일이 있었다면 그대로 사용할 수 있다

사용하지 않은 컨테이너 관리


nginx 이미지를 사용하여 생성한 컨테이너 목록 조회

docker ps -f ancestor=[image name]

ancestor : 컨테이너를 생성하는 데 사용한 이미지를 기준으로 필터링

컨테이너 종료

docker stop [container name | ID]

nginx 이미지를 사용하여 생성한 컨테이너 목록에서 id 값만 조회

docker ps -q -f ancestor=[image name]

-q(--quite) : id 출력

stop 명령어에 인자를 사용하여 해당되는 컨테이너들 모두 종료

docker stop $(docker ps -q -f ancestor=[image name])

컨테이너 삭제

docker rm [ID | 인자 사용해서 해당 컨테이너들 삭제]

인자를 사용할 때 종료된 컨테이너 이므로 -a(--all) 옵션을 사용해서 필터링 해야한다

이미지 삭제

docker rmi $(docker images -q [image name])

컨테이너 이미지 만드는 4가지 방법


기본 방법으로 빌드

이미지를 생성하기 위한 파일들이 있는 폴더 위치에서 도커 빌드 사용

docker build -t [빌드 이미지 명] .

-t(tag) : 만들어질 이미지
. : 이미지에 원하는 내용 추가 및 변경하는 데 필요한 작업 공간을 현재 디렉토리로 지정

아래는 도커 빌드에 사용된 Dockerfile

FROM openjdk:8
LABEL description="Echo IP Java Application"
EXPOSE 60431
COPY ./target/app-in-host.jar /opt/app-in-image.jar
WORKDIR /opt
ENTRYPOINT [ "java", "-jar", "app-in-image.jar" ]

FROM openjdk:8

FROM [image name]:[tag] 형식으로 이미지 가져오며 가져온 이미지
내부에서 컨테이너 이미지를 빌드, openjdk 를 베이스 이미지로 사용

LABEL description="Echo IP Java Application"

LABEL [rable]=[value] 형식으로 이미지에 부가적인 설명을 위한 레이블 추가 시 사용
Echo IP Java Application 라는 내용의 description 레이블 추가

EXPOSE 60431

컨테이너 구동할 때 어떤 포트에다가 프로세스를 띄울지 정함

COPY ./target/app-in-host.jar /opt/app-in-image.jar

COPY [host path][container path]
호스트에서 새로 생성하는 컨테이너 이미지로 필요한 파일을 복사

WORKDIR /opt

이미지의 현재 작업 위치를 opt 로 변경

ENTRYPOINT [ "java", "-jar", "app-in-image.jar" ]

ENTRYPOINT ["명령어", "옵션" ... "옵션"]
컨테이너 구동 시 ENTRYPOINT 뒤에 [] 안에 있는 명령을 실행, 콤마로 구분

컨테이너 용량 줄이기

기본 빌드하기에서 사용하던 기초 이미지 openjdk -> GCR - ditroless 로 변경
ditroless : 자바 실행을 위해 경량화된 이미지

컨테이너 내부에서 빌드하기

컨테이너에서 새로 생성된 이미지는 컨테이너 내에서 빌드를 진행하기 때문에
생성한 파일들과 내려받은 라이버러리 캐시들이 이미지에 그대로 남는다
기본 방법으로 빌드하는 이미지보다도 크기가 더 커진다

최적화해 컨테이너 빌드하기

멀티 스테이지는 도커 17.06 버전부터 지원
빌드하는 위치와 최종 이미지를 분리하여 용량을 줄임

FROM openjdk:8 AS int-build
LABEL description="Java Application builder"
RUN git clone https://github.com/iac-source/inbuilder.git
WORKDIR inbuilder
RUN chmod 700 mvnw
RUN ./mvnw clean package

FROM gcr.io/distroless/java:8
LABEL description="Echo IP Java Application"
EXPOSE 60434
COPY --from=int-build inbuilder/target/app-in-host.jar /opt/app-in-image.jar
WORKDIR /opt

쿠버네티스에서 직접 만든 컨테이너 사용


도커로 빌드한 이미지를 kubectl create deploy --image 에 넣어서 워커노드를 생성하고
-w 옵션을 이용해 상태를 체크해보면 ErrImagePull, ImagePullBackOff 가 발생한다
첫번째 이유로는 쿠버네티스에서 이미지로 워커노드를 생성할 때 외부(도커 허브)에서 받으려고 시도 한다
실행 결과를 yaml 파일로 저장해서 imagePullPolicy: Never 옵션을 넣고
kubectl apply -f [yaml file] 을 실행해 보아도 결과는 ErrImageNeverPull 이 발생
워커 노드에 컨테이너 이미지가 없으면 위와 같이 이미지를 불러서 실행시킬 수 없다
이 부분을 해결하는 방법 2가지는 아래와 같다

1.도커 허브에 이미지를 올려서 다시 내려받는 방법
2.쿠버네티스 클러스터가 접근할 수 있는 곳에 이미지 레지스트리를 만들고 받는 방법

레지스트리 구성

종류 : Quay, Harbor, Nexus Repository, Docker Registry
사용 : Docker Registry, 개인용 or 테스트에 적합

사용한 파일 3개
인증서에 필요한 추가 정보가 있는 파일 .csr
레지스트리 생성 및 구동 스크립트 파일 .sh
인증 문제시 모든 설정을 지우는 스크립트 파일 .sh
csr 인증 파일은 도커에 이미지를 올리거나 내릴 때 레지스트리에 접속하는 과정에서 주체 대체 이름이라는
추가 정보를 검증하기 때문에 요청서에 정보를 기입해 인증서를 생성하는 과정이 필요하므로 추가됨

.csr

[req]
distinguished_name = private_registry_cert_req
x509_extensions = v3_req
prompt = no

[private_registry_cert_req]
C = KR
ST = SEOUL
L = SEOUL
O = gilbut
OU = Book_k8sInfra
CN = 192.168.56.10

[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.0 = m-k8s
IP.0 = 192.168.56.10

레지스트리 생성 및 구동 .sh

#!/usr/bin/env bash
certs=/etc/docker/certs.d/192.168.56.10:8443
mkdir /registry-image
mkdir /etc/docker/certs
mkdir -p $certs
openssl req -x509 -config $(dirname "$0")/tls.csr -nodes -newkey rsa:4096 \
-keyout tls.key -out tls.crt -days 365 -extensions v3_req

yum install sshpass -y
for i in 1
  do
    sshpass -p vagrant ssh -o StrictHostKeyChecking=no root@192.168.56.10$i mkdir -p $certs
    sshpass -p vagrant scp tls.crt 192.168.56.10$i:$certs
  done

cp tls.crt $certs
mv tls.* /etc/docker/certs

docker run -d \
  --restart=always \
  --name registry \
  -v /etc/docker/certs:/docker-in-certs:ro \
  -v /registry-image:/var/lib/registry \
  -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/docker-in-certs/tls.crt \
  -e REGISTRY_HTTP_TLS_KEY=/docker-in-certs/tls.key \
  -p 8443:443 \
  registry:2

인증 문제시 설정 제거 .sh

#!/usr/bin/env bash
certs=/etc/docker/certs.d/192.168.56.10:8443
rm -rf /registry-image
rm -rf /etc/docker/certs
rm -rf $certs

yum -y install sshpass
for i in 1
  do
    sshpass -p vagrant ssh -o StrictHostKeyChecking=no root@192.168.56.10$i rm -rf $certs
  done

yum remove sshpass -y
docker rm -f registry
docker rmi registry:2

레지스트리를 생성하는 쉘스크립트 실행
이미지를 레지스트리에서 읽기 위해 IP/도메인 + 레지스트리에 등록될 이미지 이름 으로 사본 생성
docker tag [image name][tag image name ex) 192.168.56.10:8443/image name]
이미지를 사설 도커 레지스트리에 등록
docker push [tag image name]

사설 도커 레지스트리에 이미지가 등록되었는지 확인
curl https://192.168.56.10:8443/v2/_catalog -k
자체 서명 인증서를 쓰는 사이트이므로 -k(--insecure) 옵션으로 보안 검증을 생략하고 접속

kubectl apply -f [file name] 로 워커 노드에 컨테이너를 띄어서 정상적으로 작동하는지 확인

profile
엔지니어

0개의 댓글