본문 바로가기
대외활동/Google Cloud Study Jam

[Kubernetes 입문] Introduction to Docker

by 드인 2022. 7. 24.

Introduction to Docker


Introduction to Docker

 

Docker 소개 | Google Cloud Skills Boost

이 실습에서는 기본적인 Docker 컨테이너 환경 명령어를 배워봅니다. 컨테이너를 생성, 실행, 디버그하고 Google Container Registry와 이미지를 주고받는 과정을 실습하게 됩니다.

www.cloudskillsboost.google

 

1.Overview

 - Docker: 애플리케이션을 developing, shipping, running하기 위한 개방형 플랫폼

 - Docker를 사용하면, 

   1) Application인프라에서 분리하고 인프라를 managed application처럼 다룰 수 있음

   2) 더 빠르게 코드를 제공, 테스트 및 배포 → 코드 작성과 코드 실행 사이의 cycle를 단축

 - Docker는 커널 컨테이너화 기능을 application 관리, 배포에 도움이 되는 워크플로우, 도구와 결합하여 수행

 - Docker 컨테이너는 Kubernetes에서 직접 사용할 수 있음

 

2. Setup and Requirements

 - Google Cloud Platform(GCP) 환경 설정

 

3. Hello World

1) hello world 컨테이너 실행

 > Input

docker run hello-world

 > Output

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
...
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
...

  - Docker Daemon이 hello-world 이미지를 검색했지만 로컬에서 이미지를 찾지 못함

  - Docker Hub라는 공용 레지스트리에서 이미지를 가져와서 해당 이미지에서 컨테이너를 생성하고 컨테이너를 실행

 

2) Docker Hub에서 가져온 컨테이너 이미지 확인

 > Input

docker images

 > Output

REPOSITORY     TAG      IMAGE ID       CREATED       SIZE
hello-world    latest   1815c82652c0   6 days ago    1.84 kB

  - 이미지 ID는 SHA256 해시 형식

  - 프로비저닝된 Docker 이미지를 지정

 

3) hello world 컨테이너 재실행

docker run hello-world

  - 두 번째로 실행할 때 Docker Daemon은 로컬 레지스트리에서 이미지를 찾고 해당 이미지에서 컨테이너를 실행

 

4) 실행 중인 컨테이너 확인

docker ps

 

5) 실행 완료 컨테이너를 포함한 모든 컨테이너 확인

docker ps -a

  - Container ID, 컨테이너를 식별하기 위해 Docker에서 생성한 UUID, 실행과 관련된 여러 메타데이터 표시

  - 컨테이너 이름도 무작위로 생성되지만 아래 코드로 지정 가능

docker run --name [container-name] hello-world

 

4. Build

1) 이미지 빌드 방법을 Docker Daemon에 지시

mkdir test && cd test

# 도커 파일 생성 과정
cat > Dockerfile <<EOF
# 기본 상위 이미지를 지정(노드 버전 장기 지원(lts) 공식 Docker 이미지) / Use an official Node runtime as the parent image
FROM node:lts
# 컨테이너의 작업(현재) 디렉터리 설정 / Set the working directory in the container to /app
WORKDIR /app
# 현재 디렉토리의 내용을 컨테이너에 추가 / Copy the current directory contents into the container at /app
ADD . /app
# 컨테이너의 포트에서 연결을 수락 / Make the container's port 80 available to the outside world
EXPOSE 80
# node 명령을 실행하여 애플리케이션을 시작 / Run app.js using node when the container launches
CMD ["node", "app.js"]
EOF

 - Dockerfile command references

 

Dockerfile reference

 

docs.docker.com

 

2) 노드 애플리케이션 작성

cat > app.js <<EOF
const http = require('http');
const hostname = '0.0.0.0';
const port = 80;
const server = http.createServer((req, res) => {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Hello World\n');
});
server.listen(port, hostname, () => {
    console.log('Server running at http://%s:%s/', hostname, port);
});
process.on('SIGINT', function() {
    console.log('Caught interrupt signal and will exit');
    process.exit();
});
EOF

- 포트 80에서 수신 대기하고 "Hello World"를 반환하는 HTTP 서버

 

3) 노드 애플리케이션 기반 Docker 이미지 빌드

docker build -t node-app:0.1 .

 - Dockerfile이 있는 디렉토리 내에서 이 명령을 실행(.)

 - -t: 이미지에 이름과 태그를 지정

 

4) 빌드한 이미지 확인

docker images

 - node: 기본 이미지

 - node-app: 빌드한 이미지

 

5. Run

 1) 빌드한 이미지로 컨테이너 실행

docker run -p 4000:80 --name my-app node-app:0.1

2) 다른 터미널에서 서버 테스트

curl http://localhost:4000

3) 컨테이너 중지 및 제거

docker stop my-app && docker rm my-app

4) 백그라운드에서 컨테이너 시작

docker run -p 4000:80 --name my-app -d node-app:0.1
docker ps

5) 컨테이너 로그 확인

docker logs [container_id]

6) 레이어 수정

cd test

vi app.js

....
const server = http.createServer((req, res) => {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Welcome to Cloud\n'); 
});
....

docker build -t node-app:0.2 .

 - Hello World → Welcome to Cloud

 - 2단계에서 기존 캐시 계층을 사용

 - app.js를 변경했기 때문에 3단계부터 레이어가 수정됨

 

7) 새 이미지 버전으로 다른 컨테이너 실행

docker run -p 8080:80 --name my-app-2 -d node-app:0.2
docker ps
curl http://localhost:8080

- 두번째 컨테이너 테스트

curl http://localhost:4000

- 첫번째 컨테이너 테스트

 

6. Debug

1) 컨테이너 로그 확인

docker logs -f [container_id]

2) 실행 중인 컨테이너 내에서 대화형 Bash 세션 시작(다른 터미널에서)

docker exec -it [container_id] bash

 - -it: pseudo-tty를 할당하고 표준 입력을 열린 상태로 유지하여 컨테이너와 상호 작용

ls
exit

3) Docker inspect를 사용하여 Docker에서 컨테이너의 메타데이터 검사

docker inspect [container_id]
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' [container_id]

 - --format: 반환된 JSON에서 특정 필드를 검사

 - Docker inspect reference

 - Docker exec reference

 

7. Publish

 - 이미지를 Google Container Registry (gcr)에 push

 - 모든 컨테이너와 이미지를 제거하여 새로운 환경을 시뮬레이션하고, 컨테이너를 가져와 실행

 

1) gcr에서 호스팅하는 비공개 레지스트리에 이미지 push

 - 이미지에 레지스트리 이름을 태그

 - 형식: [hostname]/[project-id]/[image]:[tag]

  • [hostname]= gcr.io
  • [project-id]= 프로젝트 ID
  • [image]= 이미지 이름
  • [tag]= 선택한 문자열 태그, 기본값 "latest"
gcloud config list project
docker tag node-app:0.2 gcr.io/[project-id]/node-app:0.2
docker images
docker push gcr.io/[project-id]/node-app:0.2

2) 웹 브라우저에서 이미지 레지스트리를 방문하여 이미지가 gcr에 있는지 확인

 (1) Navigation menu > Container Registry > node-app

 (2) http://gcr.io/[project-id]/node-app

 

3) 모든 컨테이너를 중지하고 제거

docker stop $(docker ps -q)
docker rm $(docker ps -aq)

4) 노드 이미지를 제거하기 전 하위 이미지를 제거

docker rmi node-app:0.2 gcr.io/[project-id]/node-app node-app:0.1
docker rmi node:lts
docker rmi $(docker images -aq) # remove remaining images
docker images

5) 이미지 Pull하고 실행

docker pull gcr.io/[project-id]/node-app:0.2
docker run -p 4000:80 -d gcr.io/[project-id]/node-app:0.2
curl http://localhost:4000