Docker 기본

Gon Kim·2022년 10월 25일
0

Docker를 내 수준에서 사용할 때 필요한 간단한 지식을 정리한다.

내가 궁금한 것을 찾아봐 정리한다.

간단한 사용법(CLI)를 정리한다.

공식 document가 되게 친절하더라

Docker

Docker에 대해 알아본다. 모든 분야가 항상 오버헤드를 줄이고, 무언가를 빠르게 효율적으로 하기 위한 수단을 찾으려고 노력하는 것 같다. 컨테이너의 개념도 같은 맥락에서 등장했다.
지금 세대가 가꿔나가는 인프라 위에서 다음 세대는 또 어떤 부분에 집중해나갈지 궁금해진다.

1) Introduction

특정 기능을 수행하는 큰 프로그램을 만들기 위해 여러 프로그램(DB, 웹서버)등을 설치해야할 때가 있다. 다만 이러한 과정은 예상치 못하는 오류를 자주 보이기도 하며, 상당히 번거롭다. 특정 운영체제나 환경에서 그냥 잘!! 돌아가도록 미리 만들어두고 서로 통신하며 굴러가면 참 좋을 것이다.

그러나 이를 위해 하드웨어를 직접 여러대 장만하는 것은 비용 소모가 크다. 여기서 컴퓨터 안의 컴퓨터인 가상머신의 개념이 나왔다. 운영체제 위에 서로 다른 환경과 운영체제를 각각 구축하는 것이다. 하드웨어 비용 절감은 되지만, 안그래도 용량이 큰 운영체제를 그 때 그 때 설치하는 것도 굉장히 비용 소모적인 일이고, 일단 느리다.

컨테이너의 개념이 등장한다. 각각의 소프트웨어/앱은 하나의 운영체제 위에서 ‘격리된 환경’을 갖고, 그 위에서 실행된다. 이 각각의 격리된 환경을 컨테이너라고 한다. 각각의 컨테이너에는 운영체제 전체가 설치된 것이 아니고, 앱을 위한 파일들(라이브러리 등)만 설치되어있다.

이런 컨테이너 기술을 사용하는 다양한 소프트웨어가 있고, 그 중 docker가 가장 많이 쓰인다.

2) 용어 및 기본 개념

먼저 CLI 두들겨보고 나서 어떤 개념들이 필요한지 확인하고 다시 찾아 정리했다.

Architectuer

  • Docker은 client-server 구조를 사용한다고 한다.
  • Docker client는 Docker daemon에게 요청하고, docker daemon은 뒷 단에서 일을 처리한다.
  • Docker client와 daemon은 같은 host에서 실행될 수도 있고, client는 다른 host의 docker daemon에 요청을 보낼 수도 있다!!!
  • Client와 HTTP REST API로 의사소통 한다.
    • REST API를 사용한다길래 내가 아는 그 http rest api가 맞나? 싶었다. 찾아보니 맞더라..

    • https://docs.docker.com/engine/api/v1.40/를 확인해보자.

    • Web만을 위한 통신 표준인지 알았는데, 그게 아니더라. 신기하다.

    • 아래는 GET /containers/json 요청에 대한 응답 중 일부이다. container 리스트를 반환하는데, 하나의 container에 대한 정보에 다음과 같은 것들이 포함된다.

      {
      "Id": "8dfafdbc3a40",
      "Names": [],
      "Image": "ubuntu:latest",
      "ImageID": "d74508fb6632491cea586a1fd7d748dfc5274cd6fdfedee309ecdcbc2bf5cb82",
      "Command": "echo 1",
      "Created": 1367854155,
      "State": "Exited",
      "Status": "Exit 0",
      "Ports": [],
      "Labels": {},
      "SizeRw": 12288,
      "SizeRootFs": 0,
      "HostConfig": {},
      "NetworkSettings": {},
      "Mounts": []
      },

Docker daemon

  • 실제로 docker가 잘 돌아가도록 관리하는 프로그램이다. 당연히 위 introduction에서 설명한 모든 것을 수행해내기 위해 많은 일들이 일어날 것이다. 이를 docker daemon이 처리하고 우리는 이 docker daemon에게 명령하는 방식이다.

Docker Client

  • 우리가 docker daemon과 의사소통하기 위해 사용하는 프로그램
  • CLI 지원

Docker Registries

  • Docker image를 저장하는 저장소이다.
  • Docker hub을 많이들 쓴다. public한 registry이다. docker가 image 받아올 때 찾아오는 registry의 default 값

Docker Objects

  • images, containers, networks, volumes, plugins 등을 일컫는다.
    • docker compose를 공부하면 이러한 것들이 objects로서 취급되는 이유를 받아들이기 쉽다.

Host

  • Docker daemon을 통해 docker container를 띄우는 컴퓨터

Images

  • Container 생성을 위한 instruction들이 포함되는 read-only 파일이다.
  • 하나의 image를 기반으로 그 위에 다른 image를 생성해낼 수 있다.
  • image를 만들기 위해서는 Dockerfile이라는 것을 사용한다. Dockerfile에 생성하고자 하는 image를 생성하기 위한 instruction들을 적어둔다.
    • Dockerfile의 각 instruction은 image 내의 ‘layer’라는 것을 생성한다.
    • Dockerfile을 바꾸고 다시 image를 생성하면, 바뀐 layer들만 다시 생성된다.
      • 이게 진짜 신기하다

Containers

  • Image를 실행가능한 형태로 변환한 instance
  • container에 storage를 달아줄 수도 있고, 다른 네트워크에 연결할 수도 있다.
  • container의 현재 상태 위에 또 image를 만들 수도 있다.
  • container는 다른 container와 host로부터 격리되어있다. 격리 수준을 조절할 수도 있다. 예로, docker run의 -v flag는 container가 host file system과 특정 부분을 공유할 수 있도록 한다.

Docker Command

Dockerfile 작성하고, 빌드, 실행 및 중지, 디버깅, hub에 push하는 아주 기본적인 개념들 정리

# 컨테이너 실행
docker run [container]

# 이미지 확인
docker images

# 실행중인 컨테이너 확인
docker ps

# 실행중인, 실행했던 모든 컨테이너 확인
docker ps -a

# 실행중인 컨테이너 정지
docker stop CONTAINER_NAME

# 컨테이너 삭제
docker rm CONTAINER_NAME

# 이미지 삭제
docker rmi IMAGE[:TAG]

# Source img를 참조해 target_img 생성
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

# dockerhub에 push
$ docker push [OPTIONS] NAME[:TAG]

1) 빌드

Dockerfile

cat > Dockerfile <<EOF
# 공식 노드 런타임을 상위 이미지로 사용합니다.
FROM node:6
# 컨테이너의 작업 디렉토리를 /app으로 설정합니다.
WORKDIR /app
# 현재 디렉토리 내용을 /app에 있는 컨테이너에 복사합니다.
ADD . /app
# 컨테이너의 포트 80을 외부에 공개합니다.
EXPOSE 80
# 컨테이너가 시작될 때 노드를 사용하여 app.js를 실행합니다.
CMD ["node", "app.js"]
EOF
  • FROM : 상위 이미지 지정
  • WORKDIR : 작업 디렉토리 지정
  • ADD : 현재 디렉토리의 내용을 컨테이너에 추가
  • EXPOSE : 컨테이너 포트 공개, 포트 연결 허용
  • CMD : 노드 명령어를 실행

이 외에도 명령어들이 더 있다.

이미지 빌드

app.js 파일 생성 후

docker build -t node-app:0.1 .
  • -t는 name:tag 구문을 사용하여 이미지의 이름과 태그 지정
    • 위 예시의 경우 이미지 이름은 node-app, 태그는 0.1
  • 태그를 지정하지 않으면 태그가 기본 값인 latest로 지정되어 최신 이미지와 기존 이미지 구분이 어렵기에 태그를 추가하는 것을 권장
  • docker images를 찍어보면 node, node-app이 모두 보인다. node를 제거하기 위해서는 node-app을 제거해야한다. node:slim, node:alpine과 같은 노드 이미지 등을 사용하면 더 작은 이미지를 제공하기에 이식성을 높일 수 있다.

2) 실행

// 실행
docker run ([option]) [image_name]:[image_tag] ([command]) ([param])
docker run -p 4000:80 --name my-app node-app:0.1
// 백그라운드에서 컨테이너 시작
docker run -p 4000:80 --name my-app -d node-app:0.1

// 확인
curl http://localhost:4000

// 중단
docker stop my-app && docker rm my-app

// 컨테이너 확인
docker ps
  • --name 플래그를 사용하면 컨테이너 이름을 지정할 수 있다.
  • -p는 docker가 컨테이너의 포트 80에 호스트의 포트 4000을 매핑하도록 지시하는 플래그이다.
  • 컨테이너는 터미널이 실행되는 동안 유지된다. 터미널 세션에 종속 시키지 않고 백그라운드에서 실행하려면 -d 플래그를 추가한다.
docker run -p 4000:80 --name my-app
		-v [Host파일시스템]:[컨테이너파일시스템]
		node-app:0.1
  • -v 플래그는 docker를 띄운 컴퓨터 파일시스템과 컨테이너 파일시스템을 연결한다. 경로를 입력하면 된다.

3) 수정

위에서 만들었던 app.js를 수정하고, 다시 image를 build해보자

docker build -t node-app:0.2 .

실행해보면 2단계에서 기존 cache 레이어를 사용하고 있음을 알 수 있다. app.js를 변경했기에 3단계 이후부터만 레이어가 수정된다.

1, 2)와 같은 방법으로 빌드, 실행하면 된다.

4) 디버깅

// 로그 확인
docker logs [container_id]
// 컨테이너가 실행중일 때 로그 확인 ---> 무슨 차이인지 아직 모르겠다.
docker logs -f [container_id]

// 실행 중인 컨테이너에서 Bash 세션을 시작해야할 때
docker exec -it [container_id] bash
	exit 을 통해 나올 수 있다.

// 컨테이너의 메타데이터 조회
docker inspect [container_id]
// 반환된 JSON의 특정 필드 검사
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' [container_id]
  • exec의 -it 플래그는 pseudo-tty를 할당하고 stdin을 열린 상태로 유지하여 컨테이너와 상호작용할 수 있게 한다. 해당 라인을 실행해보면 Dockerfile에 지정된 WORKDIR에서 bash가 실행된 것을 확인할 수 있다.
    • tty(teletypewriter)은 리눅스 디바이스 드라이브중에서 콘솔이나 터미널을 의미한다.
    • 컨테이너에 가상의 터미널을 열어 나와 소통할 수 있게 하는 것이다.
    • docker exec -it [container_id] /bin/bash와 같이 실행시킬 숫도 있다.

5) 게시

docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

# hub으로 올릴 이미지를 복사
docker tag [old_img_name]:[old_img_tag] [hub_account]/[hub_repository]
docker tag node-app:0.2 my_account/project-id/node-app:0.2
# hub으로 push
docker push [hub_account]/[hub_repository]
  • tag 커맨드를 통해 이미지를 복사할 수 있다.
  • repository는 이름이 같지만 tag가 다른 이미지들이다.
  • repository 이름에 네임스페이시를 넣고 /로 구분 가능하다. 팀내 소유권 등 식별시 가시적으로 확인 가능
    • 이렇게 한다고 계층적으로 관리되거나 하는 것은 아니다.

6) 테스트

# pull
docker pull [hub_account]/[hub_repository]
docker pull gcr.io/[project-id]/node-app:0.2

# 실행 및 확인
docker run ..해당이미지..
curl http://localhost:...

Ref

Docker Documentation

Docker Engine API v1.41 Reference

docker

레지스트리, 리포지토리, 이미지, 아티팩트 정보 - Azure Container Registry

profile
응애

0개의 댓글