주니어 개발자 1호

[Chapter 1]쿠버네티스 스터디 1주차 - Docker 본문

Server 관련

[Chapter 1]쿠버네티스 스터디 1주차 - Docker

No_1 2022. 6. 30. 15:22

Docker란? 애플리케이션을 개발, 출시, 실행하는 데 사용하는 개방형 플랫폼

도커의 장점, 사용해야 하는 이유

  1. 인프라에서 애플리케이션을 분리하여, 관리형 애플리케이션처럼 처리할 수 있습니다.
  2. 코드를 더욱 빠르게 출시, 테스트, 배포 하고 코드 작성과 실행 주기 단축하는데 도움이 됩니다.
  3. 컨테이너는 쿠버네티스에서 직접 사용할 수 있으므로, 쿠버네티스 엔진에서 쉽게 사용할 수 있습니다.
  4. 컨테이너는 환경에 구애받지 않고 실행하는 기술
  5. ( 필요한 패키지를 담아서, 컨테이너에 싣는다 라는 표현이 어울릴것 같습니다. )
  6. 다른 사람이 만들어둔 서버를 소프트웨어 가져오듯 사용할 수 있습니다.

 

터미널 켜기

 

Hello World in Dockers

[ 목적 ] - hello-world 이미지 실행

[ 실행 순서 ]

터미널에 docker run hello-world 실행시

  1. local ( 자신의 컴퓨터 )에서 hello-world 라는 이미지를 찾지 못함
  2. DockerHub라는 공개 레지스트리에서 해당 이미지를 가져왔고, 컨테이너를 생성하고 실행함
  3. 재 실행시에는 이미 local ( 자신의 컴퓨터 ) 에 있으므로 Hub에서 가져오지 않음.
# 이미지를 찾지 못함
Unable to find image 'hello-world:latest' locally
# 라이브러리에서 hello-world를 pull 함
latest: Pulling from library/hello-world
9db2ca6ccae0: Pull complete
Digest: sha256:4b8ff392a12ed9ea17784bd3c9a8b1fa3299cac44aca35a85c90c5e3c7afacdc
Status: Downloaded newer image for hello-world:latest
# 실행 결과
Hello from Docker!
This message shows that your installation appears to be working correctly.
...

[ 부가 확인 ]

1️⃣ docker images ⇒ 이미지 목록

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

2️⃣ docker ps ⇒ 실행 중인 컨테이너 확인
docker ps -a ⇒ 종료된 컨테이너까지 출력

CONTAINER ID        IMAGE               COMMAND             CREATED             
STATUS              PORTS               NAMES

 

빌드

[ 빌드란? ]

터미널 기준 Dockerfile을 기준으로 컨테이너를 실행하기 위한 이미지를 생성해주는 작업

[ 목적 ] - Dockerfile 생성, 이미지 생성

[ 실행 순서 ]

  1. 디렉토리 test 생성 후 진입 ( mkdir test && cd test )
  2. Dockerfile 만들기
  3. app.js 파일 생성 ( node 어플리케이션 )
  4. 빌드 - 명령어( . - dot 까지 포함 ) docker build -t node-app:0.1 . ( 이름: node-app, 태그 0.1 )
mkdir test && cd test
cat > Dockerfile <<EOF
#공식 노드 런타임 (version 6)을 상위 이미지로 사용합니다.
FROM node:6 
# 컨테이너의 작업 디렉토리 ( 최상위: /app )
WORKDIR /app 
# 현재 디렉토리 내용을 /app에 있는 컨테이너에 복사. ( COPY가 아니고..? )
ADD . /app
# 컨테이너 PORT 80 세팅
EXPOSE 80
# 컨테이너가 시작될 때 수행할 명령어 app.js를 실행한다.
CMD ["node","app.js"]
EOF
cat > app.js <<EOF
// http 모듈 
const http = require('http');
const hostname = '0.0.0.0';
const port = 80;

// 서버 생성시, log에 Hello World\\n 실행
const server = http.createServer((req, res) => {
    res.statusCode = 200;
      res.setHeader('Content-Type', 'text/plain');
        res.end('Hello World\\n');
});

// 서버에 <http://localhost:80> 으로 접속시, 아래 log가 출력
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

 

이미지 실행

  1. node-app:0.1 실행 ( local 4000번 포트에 , 컨테이너 listen port 80 , 이름: node-app 태그: 0,1 )
  2. 다른 터미널을 열어 요청 localhost:4000번에 요청 curl [<http://localhost:4000>](<http://localhost:4000>)
  3. 도커 컨테이너 중단 및 삭제 docker stop my-app && docker rm my-app
  4. 도커 재 실행 ( local 4000port, 컨테이너 listen port 80 이름: myapp, detached 모드 , docker run -p 4000:80 --name my-app -d node-app:0.1
  5. docker ps를 통해 container id를 확인
  6. docker ps 실행 후 container id 확인
  7. 로그 확인 docker logs [container_id]
  8. nano, vim, vi등으로 app.js 편집 ( 검색 하면 나옵니다! ) → res.end(’여기의 값’)
  9. 이미지 re build 태그가 달라짐. 0.2 docker build -t node-app:0.2 .
  10. 컨테이너 실행 ( 0.2 ) docker run -p 8080:80 --name my-app-2 -d node-app:0.2
  11. 컨테이너 확인 docker ps
  12. 컨테이너 테스트 curl [<http://localhost:8080>](<http://localhost:8080>) ( 자신이 설정한 메세지 확인 )
docker run -p 4000:80 --name my-app node-app:0.1
# -> 결과: Server running at <http://0.0.0.0:80/>

curl [<http://localhost:4000>](<http://localhost:4000>) 
# -> 결과: Hello World

docker stop my-app && docker rm my-app
# -> dokcer 중지 및, my-app 컨테이너 삭제

docker run -p 4000:80 --name my-app -d node-app:0.1
# -> docker 실행, detached 모드로 인해 백그라운드로  실행 되며 logs를 요청할 수 있다.

vi app.js 
# -> 경로 맞추어서 실행, 이후 res.end("Test World 등 적고싶은값");

docker build -t node-app:0.2 . 
# -> docker image 다시 빌드, tag:0.2로 변경
# 이때, 2단계에서 기존 캐시레이어를 사용하고 있음. app.js를 변경하였기에, 3단계 이후부터 
# 레이어가 수정 되어 보여짐

docker run -p 8080:80 --name my-app-2 -d node-app:0.2
# 4000 port는 위에서 사용중이기에 , 8080 port로 변경하여 사용

docker ps 
# 실행 예시 -> image 태그 다른것이 두개 올라 가있음.
# CONTAINER ID     IMAGE             COMMAND            CREATED
# xxxxxxxxxxxx     node-app:0.2      "node app.js"      53 seconds ago      ...
# xxxxxxxxxxxx     node-app:0.1      "node app.js"      About an hour ago   ...

curl <http://localhost:8080>
# 컨테이너 테스트

 

디버깅

[ 목적 ]

실행 중 오류, 특이사항을 확인 하기 위한 log 확인

[ 실행 순서 ]

  1. 컨테이너 로그 확인 → docker logs -f [container_id]
    • container_id 는 docker ps -a, docker ps 등으로 확인
  2. 실행 중인 컨테이너에서 대화식으로 bash 활성화 ( 다른 터미널 열기 )
    • -it 의 경우
      1. 사용자의 입 출력을 도와주는 -i, —interactive
      2. 사용자가 터미널 환경을 쓸 수 있게 해주는 -t, -tty
      가 합쳐짐.
  3. 명령어 입력: docker exec -it [container_id] bash
  4. 현재 dir 파일 목록 확인 이후 종료
  5. 명령어 입력: ls , exit
  6. 메타데이터 검토
    • —format을 통해 반환된 JSON의 특정 필드를 검사 할 수 있다.
  7. 명령어 입력: docker inspect [container_id]
docker logs -f container_id 
# container_id는 docker ps, ps -a등으로 확인이 가능

Server running at <http://0.0.0.0:80/>
# 결과

docker exec -it [container_id] bash
# 다른 터미널-> 위 명령어 입력 ( 해당 컨테이너에 접근하여, 통신을 할 수 있음 )

root@xxxxxxxxxxxx:/app#
# 위 명령어 결과

ls
# 파일 목록 확인

Dockerfile  app.js
root@xxxxxxxxxxxx:/app
# 파일 목록 확인 결과

docker inspect [container_id]
# 메타 데이터 검토 1

[
    {
        "Id": "xxxxxxxxxxxx....",
        "Created": "2017-08-07T22:57:49.261726726Z",
        "Path": "node",
        "Args": [
            "app.js"
        ],
...
#메타 데이터 검토 결과 1

docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' [container_id]
# 메타 데이터 검토 2

192.168.9.3
#메타 데이터 검토 결과 2

배포

[ 목적 ]

만들어진 컨테이너를 배포, push 하기 위함

[ 사전 유의 ]

GCR에서 호스팅하는 비공개 레지스트리에 이미지를 푸시하려면 이미지에 레지스트리 이름으로 태그를 지정해야 합니다. 양식은 [hostname]/[project-id]/[image]:[tag] 입니다.

  • [hostname]= gcr.io
  • [project-id]= 프로젝트 ID
  • [image]= 이미지의 이름
  • [tag]= 문자열 태그, 기본값인 'latest'

[ 실행 순서 ]

  1. 프로젝트 아이디 검색
  2. 명령어 : gcloud config list project
  3. 태그 변경 or 추가 및 확인docker tag node-app:0.2 [gcr.io/[project-id]/node-app:0.2](<http://gcr.io/%5Bproject-id%5D/node-app:0.2>)
  4. docker images
  5. 명령어
  6. GCR 로 PUSH
  7. 명령어 : docker push gcr.io/[project-id]/node-app:0.2
  8. 사이트 확인 - http://gcr.io/[project-id]/node-app
  9. 모든 컨테이너 중지 , 제거, node:6의 하위 이미지 제거 → 확인docker stop $(docker ps -q) docker rm $(docker ps -aq) docker rmi node-app:0.2 [gcr.io/[project-id]/node-app](<http://gcr.io/%5Bproject-id%5D/node-app>) node-app:0.1 docker rmi node:6 docker rmi $(docker images -aq) # remove remaining images docker images
  10. 명령어:
  11. 이미지 다운로드 후 실행, 테스트
  12. docker pull [gcr.io/[project-id]/node-app:0.2](<http://gcr.io/%5Bproject-id%5D/node-app:0.2>) docker run -p 4000:80 -d [gcr.io/[project-id]/node-app:0.2](<http://gcr.io/%5Bproject-id%5D/node-app:0.2>) curl [<http://localhost:4000>](<http://localhost:4000/>)
gcloud config list project
# 프로젝트 ID 검색

[core]
project = [project-id]
Your active configuration is: [default]
# 프로젝트 ID 검색 결과

docker tag node-app:0.2 gcr.io/[project-id]/node-app:0.2
# 태그 변경

docker images
# 이미지 확인

REPOSITORY                      TAG         IMAGE ID          CREATED
node-app                        0.2         76b3beef845e      22 hours ago
gcr.io/[project-id]/node-app    0.2         76b3beef845e      22 hours ago
node-app                        0.1         f166cd2a9f10      26 hours ago
node                            6           5a767079e3df      7 days ago
hello-world                     latest      1815c82652c0      7 weeks ago
# 이미지 확인 결과

docker push gcr.io/[project-id]/node-app:0.2
# GCR 푸시

docker stop $(docker ps -q)
docker rm $(docker ps -aq)
# 컨테이너 중지, 제거

docker rmi node-app:0.2 gcr.io/[project-id]/node-app node-app:0.1
docker rmi node:6
docker rmi $(docker images -aq) # remove remaining images
docker images
# node 하위 이미지 제거, 노드 이미지 제거

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
# 제거 후 이미지 확인

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>
# GCR에 올린 IMAGE DOWN 및 실행, 접근

Welcome to Cloud
# 실행 결과

[ 옵션 값 ] - 참고사항

—name : 컨테이너 이름을 설정합니다.

-i , —interactive : 사용자가 터미널에서 입 출력을 할 수 있게 해준다.

-t , —tty : 터미널 환경을 사용할 수 있게 해준다.

-d, —detach : Detached 모드, 백 그라운드에서 컨테이너가 실행 됩니다.

-a, —attach : 컨테이너 표준 ( 입력, 출력, 에러 ) 를 연결합니다.

-p, —publish : 호스트와, 컨테이너를 연결 ( -p 3000:80 // 호스트 port: 컨테이너port)

—rm : 컨테이너 종료시 컨테이너 자동 제거

참고

https://choseongho93.tistory.com/287 https://khj93.tistory.com/entry/Docker-Docker-option-명령어-목록

gcloud 전체 설명서 : https://cloud.google.com/sdk/gcloud

Docker 명령어 참고 : https://docs.docker.com/engine/reference/builder/#known-issues-run

Docker inspect 참고 : https://docs.docker.com/engine/reference/commandline/inspect/#examples

Docker exec 참고 : https://docs.docker.com/engine/reference/commandline/exec/