쿠버네티스는 오프젝트라는 개념으로 각 오프젝트를 정의해놓는다. 쿠버네티스내에서 사용되는 오브젝트는 가장 기본적인 구성단위를 의미한다. 즉 쿠버네티스를 돌리는 것은 이 오브젝트들의 조합으로 이루어 진다..오프젝트는 쿠버네티스에서 쓰이는 단위이다. Pod은 컨테이너의 집합이다. 네임스페이스는 논리적인 분리의 단위로, 네임스페이스 내에 각 리소스들을 할당해서 관리할 수 있다. 가령 클러스터내에 개발, 운영, 테스트의 각각의 네임스페이스를 두어, 자원을 원하는 만큼만 할당할 수 있다.
아래와 같이 쿠버네티스 내의 어떤 오브젝트인지 확인 할 수 있다. 엄청 많지만 이를 다 외울 필요는 없고 가장 중요한 Namespace, Pod, Deployments, Replicaset 정도만 이해하고 나머지는 차근차근 이해하는 것이 권장된다.
클러스터 내 자원을 각기 그룹 짓기 위한 논리적인 분리단위이 네임스페이스다. 군대를 다녀온 사람이면, 이해되는 비유일 수 있는데, 1중대, 2중대와 같은 개념이다. 이 1중대, 2중대가 네임스페이스면, 중대 안에 실제로 일을하는 소대(Pod) 소대 안에 여러 컨테이너(기간병)정도로 이해할 수 있다. 즉, Pod, Service, Deployment을 하나로 묶어 네임스페이스를 구성할 수 있다. 쿠버네티스가 마스터노드 외에 워커노드들이 있는데, API을 기준으로해서 이런 클러스터가 여러개 있는 것처럼 사용하기위해 쓰는 것이다.
중대 하나가 네임스페이스에 비유할 수 있다고 했다. 1중대 내에 1소대가 2개 있을 수 있을까? 없다. 1소대가 2개 있으면 소대의 구분이 어렵기 때문이다. 따라서, 네임스페이스 내에서는 독립적인 이름을 가진 오브젝트를 생성할 수는 없지만, 서로 다른 네임스페이스에서는 같은 이름을 가진 오브젝트를 생성할 수 있다. 그림으로보면 아래와 같다. 이 싱글 클러스터에서 네임스페이스에 자원을 할당할 때도, 그룹단위로 자원을 할당할 수도 있다. 네임스페이스 A는 운영용이어서 풍부한자원을 위해 CPU 100, MEM:100GB, 네임스페이스 B에는 테스트용이어서 CPU:20, MEM:16GB을 줄 수 있다. 군보급을 중대 1, 중대 2에 맞춰서 보급하는 것과 유사하다!
이제 중대에 해당하는 네임스페이스를 하나 만들어본다. 네임스페이스는 보통 YAML파일을 이용해서 다음과 같이 생성한다. 아래와 같이 vim으로 yaml파일을 작성한다. 그리고 kubectl apply 을 이용해서 생성한다. -f 옵션은 yaml파일의 경로를 직접 지정해줄 때 사용한다.
이렇게 만든 네임스페이스는 다음의 명령어로 조회가 가능하다. "kubectl get [오브젝트 타입]"명령어로 조회할 수 있고 pod, namespace, 등등을 쓸 수 있다. 아래와 같이 네임스페이스를 조회하여 NAME이 myfirst-test인 네임스페이스를 만들어 낼 수 있다.
파드(Pod)는 쿠버네티스에서 생성하고 관리할 수 있는 배포 가능한 가장 작은 컴퓨터 단위이다. 파드(=고래 떼, 영어로는 Pod of whales임)라고 불리는 것은 하나 이상의 컨테이너를 포함한다. 아래의 그림처럼 각각의 고래를 도커 이미지로부터 만든 도커 컨테이너라면, 파드는 이렇게 만든 컨테이너들의 집합이 된다. 1고래 = 1컨테이너, N고래 = 파드가 된다.
파드를 구성하면 무엇이 좋은가요라는 질문을 할 수 있는데, 한번에 여러컨테이너를 그룹단위로 컨트롤이 가능하다. 파드내의 컨테이너는 클러스터의 동일한 물리에서 자동으로 같은 위치에 배치되고, 함께 스케줄된다. 즉 리소스와 의존성을 고유하고, 통신할 수 있다. 즉, 파드는 기본적으로 파드에 속한 컨테이너에 네트워킹, 스토리지가 공유된다. 공식 문서에서는 "네트워크 네임스페이스를 공유한다"라고 표현하는데, 쉽게 말해 파드 내의 주소는 IP가 동일하다는 것이다. 따라서, localhost로 서로 통신이 가능하다. 또한, 같은 파드내에서는 모든 컨테이너들이 공유 볼륨을 갖는다. 파드 A안에 컨테이너1과 컨테이너2가 서로 같은 물리적인 공간에 있기 때문에, 같은 디스크 공간에 접근해서 사용할 수 있다. 예를 들어, 컨테이너 1이 작성한 txt파일을 컨테이너2가 쓸 수 있는 것 이다 (=볼륨이 동일하다라고 표현한다).
아래와 같이 파드내에 'ngnix'을 실행하는 컨테이너를 띄울 수 있다. apiVersion은 단순히 V1이라는 것이고, 유심히 봐야할 것은 kind: Pod인 것이다. metdata내에는 name: nginx라는 이름으로 pod을 띄운다는 것이며, spec내의 내용들이 컨테이너로 띄워진다. 아래와 같이 작성한 pod의; yaml파일이 있으면 kubectl apply -f <pod을 작성한 yaml파일주소>로 실행하면된다.
* 도커이미지? 도커 이미지는 도커에서 필요한 서버 프로그램 + 소스코드 + 실행 파일로, 프로그램을 구동하기위한 종합선물세트이다. 추가적인 설치등이 필요없게 하나의 포장으로 엮어놓은 패키징된 파일을 의미한다. 예를 들어, 스타크레프트 2를 베틀넷클라이언트로 설치할 수 있지만, 윈도우 + 베틀넷클라이언트로 이미 깔린 코드 + 그레픽카드 드라이버 등을 한 번에 포장해서 도커이미지로 만들어놓으면, 똑같은 시스템을 가진 사람이 도커이미지로
* 도커 컨테이너(Docker container) ? 이미지를 실행한 상태를 의미. 패키징된 도커이미지를 격리된 동간에서 동작시키는 것(기술)을 의미한다.
혹시, 도커가 사용이 중지되어서 다시 시작하고 싶다면, docker start을 하면된다.
# 도커가 중지된 경우 docker ps -a로 확인가능
# -a option: 프로세스 중인 모든 컨테이너(all)을 확인
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d70fbbd0ee4b ubuntu "bash" 2 hours ago Exited (137) About an hour ago my_ubuntu
# 도커 시작 (ID로)
docker start d70fbbd0ee4b # 또는
# 도커 시작 (name으로)
docker start my_ubuntu
도커이미지 빌딩을 위한 Dockerfile 작성법
도커 컨테이너는 도커 이미지가 실제 구동되는 것을 의미하고, 하나의 도커 이미지로 어려 도커컨테이너를 실행시킬 수 있다. 비유하자면, 도커 컨테이너가 밀키트 만드는 제조법으로 끓여낸 부대찌게라면, 도커이미지는 밀키트 제조 레시피 및 재료이다. 위에서는 도커이미지를 도커허브(Docker Hub)에서 다운로드받아서 사용했고, 이를 이용해서 도커 컨테이너를 구동하였다. 그렇다면, 도커이미지를 만들기 위해서는 어떤 것들이 필요한가? 이 정답은 Dockerfile이다. Dockerfile은 도커이미지를 만들기 위한 레시피를 의미한다. 이 레시피에는 어떤 파일들을 참조하고있는지, 어떤 과정이 진행되는지 파악할 수 있다.
Dockerfile 에서 사용되는 명령어의 모음
아래와 같이 도커파일로부터 이미지를 만들 때 쓸 수 있는 명령어는 다음과 같다. 주의할 것은 RUN은 이미지를 만들 때 실행되는 코드이며, ENTRYPOINT, CMD은 컨테이너를 만들고나서 실행되는 코드이다.
명령어
기능
예시
FROM
새로운 이미지를 생성할 때, 기반으로 상용할 이미지를 지정. 주로 OS을 지정한다. 버전까지 지정해주는 것이 좋다. (어짜피 버전까지 지정해서 패키징해야, 플렛폼 독립적으로 쓸 거니깐).
Dockerfile은 반드시 FROM 구문으로 시작해야한다. 이미지가 내 로컬 docker 이미지가 없어도 손쉽게 퍼블릭 리포지토리에서 가져올 수 있다.
FROM ubuntu:18.04
ENV
환경변수를 할당하고 싶을 때 사용
ENV PROJECT_DIR MY_DIR
: 도커이미지을 만들 때, PROJECT_DIR 환경변수에는 MY_DIR을 할당하라는 명령어
WORKDIR
shell의 cd 명령문처럼 컨테이너 상에서 작업 디렉토리로 전환을 위해 사용됨
COPY .
호스트 컴퓨터에 있는 디렉터리나 파일을 Docker이미지 내부로 복사하기위해 사용된다. 도커 컨테이너는 격리된 공간에서 패키징된 이미지를 실행한다고 했기에 별도의 호스트컴퓨터(진짜 물리적인 컴퓨터)내에 있는 자료를 가져오기위해서는 별도의 명령어가 필요하다. 이 명령어가 COPY 명령어이다
docker run <image-name> [CMD]의 명령어에서 CMD가 없는 경우에 디폴트로 돌리기 위함이거나, 인자를 받기위함으로 사용된다.
docker run 뒤에 CMD가 없으면 default로 실행, 다른명령어가 있으면 실행이 안됨
FROM 명령어: 아래와 같이 dockerfile을 하나 작성하고, ubuntu:18.04을 작성한다. 왠만하면 버전명까지 넣어준다. docker build -t [이미지명]으로 도커이미지를 빌딩한다.
# vim을 이용하여 dockerfile을 작성
vim dockerfile
# vim 내 내용
FROM ubuntu:18.04
# vim을 빠져나옴
$ docker build -t my_ubuntu:first .
# 출력
[+] Building 1.3s (5/5) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 31B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/ubuntu:18.04 1.2s
=> CACHED [1/1] FROM docker.io/library/ubuntu:18.04@sha256:478caf1bec1afd54a58435ec681c8755883b7eb843a8630091890 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:d513fc32a2db453cb336aae40870e42a81451570aadbdc25e1662fb07dcfb1b0
도커 이미지 빌딩 결과는 다음과 같다. 아래와같이 도커리포지토리 이름은 my_ubuntu이며 ":first"으로 적어주었던부분은 TAG란에 들어갔다. 실제로는 TAG란에는 주로 버전명을 기입해서 소프트웨어의 버전관리를 용이하게 할 수 있다.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 27941809078c 2 weeks ago 77.8MB
my_ubuntu first d513fc32a2db 2 weeks ago 63.1MB
도커 RUN은 연속해서 실행할 때 마다 새로운 레이어가 생성이 된다. 예를 들어 RUN을 두번 실행되면, FROM으로 생성된 이미지 -> 컨테이너로 생성 -> 첫 번째 RUN을 실행하여 얻은 이미지 -> 첫 번째 RUN을 실행하여 얻은 이미지에서 컨테이너를 만듬 -> 이 컨테이너에서 두 번째 RUN을 실행 -> 이 내용을 이미지로 저장. 아래와같이 dockerfile을 하나 생성하고 이미지 빌딩과정을 하나 추적해보자.
이제 dockerfile을 하나 작성하여 docker image을 하나 생성해보자. 아래의 dockfile을 이용해서 빌딩된 도커이미지의 로그를 아래와 같이 이해할 수 있다.먼저 FROM 에 적인 ubuntu:18.04가 docker이미지에 없기에 docker.io에서부터 다운로드받아온다. 그다음에 캐시를 해놓는다.캐시해놓은 이미지로 다시 컨테이너를 띄우고, 그 후 RUN apt-get-y udpate을 한다. 그 후에 다시 이미지 캐시하고 다시 컨테이너를 띄우고 마지막 RUN apt-get -y install curl을 실행한다. 마지막에 RUN apt-get -y install curl까지 완료되면 해당 이미지를 내뱉는다.
# dockerfile
FROM ubuntu:18.04
RUN apt-get -y update
RUN apt-get -y install curl
# docker image build
docker build -t my_ubuntu:v1.0 .
# 출력
docker build -t my_ubuntu:v1.0 .
[+] Building 49.9s (7/7) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 108B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/ubuntu:18.04 1.5s
=> CACHED [1/3] FROM docker.io/library/ubuntu:18.04@sha256:478caf1bec1afd54a58435ec681c8755883b7eb843a8630091890 0.0s
=> [2/3] RUN apt-get -y update 21.1s
=> [3/3] RUN apt-get -y install curl 26.9s
=> exporting to image 0.2s
=> => exporting layers 0.2s
=> => writing image sha256:a6d72fef1af26555d21b78e4ca5e985bfa82df9dfcd6c8d37dd69d0178e93a32
아래와 같이 docker buil을 실행하면 처음에 Ubuntu 18.04을 베이스로하는 Container을 띄우고, 그 위에 layer 1. layer 2을 쌓아 최종 image을 만든다. 그렇게 만든 이미지는 추가적으로 변경할 수 없고 READ ONLY상태이다. 이를 container로 비로서 띄워야만 컨테이너 내부에서 파일도 쓰고 읽고 할 수 있다.
생성된 도커 이미지는 아래와 같이 삭제할 수 있다.
$ docker images
# 출력
REPOSITORY TAG IMAGE ID CREATED SIZE
my_ubuntu v1.0 a6d72fef1af2 9 minutes ago 119MB
ubuntu latest 27941809078c 2 weeks ago 77.8MB
$ docker rmi a6d72fef1af2
# 출력
Untagged: my_ubuntu:v1.0
Deleted: sha256:a6d72fef1af26555d21b78e4ca5e985bfa82df9dfcd6c8d37dd69d0178e93a32