Chapter 01. Docker 소개
시작 전.
- Google Cloud 기본 창
사진첨부
- Cloud BashShell
사진첨부
사진첨부
잘 열린 것을 확인할 수 있다.
개요
Docker
: 애플리케이션을 개발, 출시, 실행하는 데 사용하는 개방형 플랫폼.
- Docker 컨테이너 빌드, 실행, 디버그하기
- Docker Hub 및 Google Artifact Registry에서 Docker 이미지 가져오기
- Docker 이미지를 Google Artifact Registry로 푸시하기
시작
- 사용 중인 계정 이름 목록 표시
gcloud auth list
사진첨부
- 프로젝트 ID 목록 표시
gcloud config list project
사진첨부
작업 01. Hello World
- 먼저 Cloud Shell을 열고
hello world 컨테이너를 실행
한다.
docker run hello-world
사진첨부
- 결과는
Hello from Docker!
를 반환한다. - Docker 데몬이 hello-world 이미지를 검색했으나 로컬에서 이미지를 찾지 못했고, Docker Hub라는 공개 레지스트리에서 이미지를 가져오고, 가져온 이미지에서 컨테이너를 생성하고, 컨테이너를 실행했다.
- Docker Hub에서 가져온 컨테이너
이미지를 확인
하기.
docker images
사진첨부
- 위와 같은 결과는 Docker Hub 공개 레지스트리에서 가져온 이미지이다.
- 이미지 ID는
SHA256 해시
형식임. - 여기서는 프로비저닝된 Docker 이미지를 지정한다.
- Docker 데몬이 로컬에서 이미지를 찾을 수 없으면 기본적으로 공개 레지스트리에서 이미지를 검색함.
- 컨테이너
다시 실행
하기
docker run hello-world
사진첨부
- 두 번째 실행했을 때, Docker 데몬이 로컬 레지스트리에서 이미지를 찾은 뒤 이 이미지에서 컨테이너를 실행하였음을 확인할 수 있음.
- Docker 데몬이 반드시 Docker Hub에서 이미지를 가져올 필요는 없음.
실행 중인 컨테이너 확인
docker ps
사진첨부
- 실행중인 컨테이너가 없다. 전에 실행한 hello-world 컨테이너를 이미 종료했다.
- 실행이 완료된 컨테이너를 포함하여 모든 컨테이너 보기.
docker ps -a
사진첨부
- Docker가 컨테이너를 식별하기 위해 생성한 UUID인
CONTAINER ID
와 실행에 관한 추가 메타데이터가 표시된다. - 컨테이너
Names
도 무작위로 생성되지만docker run --name [container-name] hello-world
를 사용하여 지정할 수 있음.
작업 02. 빌드
- 간단한 노드 애플리케이션을 기반으로 한 Docker 이미지를 빌드하기.
test
라는 이름의 폴더를 만들고 이 폴더로 이동하기.
mkdir test && cd test
사진첨부
Dockerfile
만들기
cat > Dockerfile <<EOF
# 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
# Run app.js using node when the container launches
CMD ["node", "app.js"]
EOF
- 첫 번째 줄 : 기본 상위 이미지를 지정함. 이 경우 기본 상위 이미지는 노드 버전 장기적 지원(LTS)의 공식 Docker 이미지임.
- 두 번째 줄 : 컨테이너의 (현재) 작업 디렉터리를 설정.
- 세 번째 줄 : 현재 디렉터리의 콘텐츠(
"."
로 표시)를 컨테이너에 추가함. - 컨테이너의 포트를 공개하여 해당 포트에서의 연결을 허용하고 마지막으로 노드 명령어를 실행하여 애플리케이션을 시작함.
- 노드 애플리케이션 생성
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 서버임.
사진첨부
- Dockerfile이 있는 디렉터리에서 다음 명령어를 실행한다. 현재 디렉터리를 의미하는
"."
를 주의하자.
docker build -t node-app:0.1 .
사진첨부
이 명령어는 시간이 조금 걸린다.
결과는 다음과 비슷하게 출력됨.
Sending build context to Docker daemon 3.072 kB
Step 1 : FROM node:lts
6: Pulling from library/node
...
...
...
Step 5 : CMD node app.js
---> Running in b677acd1edd9
---> f166cd2a9f10
Removing intermediate container b677acd1edd9
Successfully built f166cd2a9f10
-t
:name:tag
문법을 사용하여 이미지의 이름과 태그를 지정하는 역할을 함. 이미지 이름은node-app
이고태그
는0.1
임. Docker 이미지를 빌드할 때는 태그를 사용하는 것이 좋음. 태그를 지정하지 않으면 태그가 기본값인latest
로 지정되어 최신 이미지와 기존 이미지를 구분하기 어려워짐.
- 빌드한 이미지 확인하기.
docker images
사진첨부
node
는 기본 이미지,node-app
은 빌드한 이미지.node
를 삭제하려면 우선node-app
을 삭제해야 함. 이미지의 크기는 VM에 비해 상대적으로 작음.node:slim
및node:alpine
과 같은 노드 이미지의 다른 버전을 사용하면 더 작은 이미지를 제공하여 이식성을 높일 수 있음.- 노드의 공식 저장소에서 모든 버전을 확인할 수 있음.
작업 03. 실행
- 빌드한 이미지를 기반으로 하는 컨테이너를 실행함.
docker run -p 4000:80 --name my-app node-app:0.1
사진첨부
--name
플래그를 사용하면 원하는 경우 컨테이너 이름을 지정할 수 있음.-p
는 Docker가 컨테이너의 포트 80에 호스트의 포트 4000을 매핑하도록 지시하는 플래그임.http://localhost:4000
에서 서버에 접속할 수 있다. 포트 매핑이 없으면 localhost에서 컨테이너에 접속할 수 없다.
- 다른 터미널을 열고(Cloud Shell에서
+
아이콘을 클릭) 서버를 테스트하기.
curl http://localhost:40
사진첨부
- 초기 터미널이 실행되는 동안 컨테이너가 실행됨. 컨테이너를 터미널 세션에 종속시키지 않고 백그라운드에서 실행하려면
-d
플래그를 지정해야 함.
- 초기 터미널을 닫은 후 컨테이너를 중지하고 삭제하기.
docker stop my-app && docker rm my-app
사진첨부
- 백그라운드에서 컨테이너를 시작하기.
docker run -p 4000:80 --name my-app -d node-app:0.1 docker ps
사진첨부
docker ps
의 출력된 결과에서 컨테이너가 실행중임을 확인할 수 있음.docker logs [container_id]
를 실행하면 로그를 볼 수 있음.
- 참고) 앞부분에 입력한 문자들로 컨테이너를 고유하게 식별할 수 있다면 전체 컨테이너 ID를 입력할 필요는 없다. 예를 들어 컨테이너 ID가
17bcaca6f....
인 경우docker logs 17b
를 실행할 수 있다.
docker logs d534dc739701
사진첨부
애플리케이션 수정하기.
- Cloud Shell에 앞서 실습에서 만든 테스트 디렉터리를 열기.
cd test
- 원하는 텍스트 편집기(예: nano 또는 vim)fh
app.js
를 편집하고 ‘Hello World`를 다른 문자열로 바꾸기.
vi app.js
사진첨부
사진첨부
- 새 이미지를 빌드하고
0.2
로 태그를 지정하기.
docker build -t node-app:0.2 .
사진첨부
- 2단계에서 기존 캐시 레이어를 사용하고 있음을 확인할 수 있다. 3단계 이해부터는
app.js
를 변경했기 때문에 레이어가 수정 되었다.
- 새 이미지 버전으로 다른 컨테이너를 실행하기. 이때 호스트 포트를 80 대신 8080으로 매핑하는 방법을 확인하기. 호스트 포트 4000은 이미 사용 중이므로 사용할 수 없음.
docker run -p 8080:80 --name my-app-2 -d node-app:0.2
docker ps
사진첨부
- 컨테이너 테스트하기.
curl http://localhost:80
사진첨부
- 처음 작성한 컨테이너를 테스트하기.
curl http://localhost:4000
사진첨부
작업 04. 디버그
- 디버깅 사례 살펴보기
docker logs [container_id]
를 사용해 컨테이너의 로그를 볼 수 있음. 컨테이너가 실행 중일 때 로그 출력을 확인하려면-f
옵션을 사용함.
docker logs -f [container_id]
사진첨부
- 실행 중인 컨테이너에서 대화형 Bash 세션을 시작해야 할 수 있다.
- 이 경우
docker exec
를 사용함. 다른 터미널을 열고(Cloud Shell에서+
아이콘을 클릭) 다음 명령어를 작성하기.
docker exec -it [container_id] bash
-it
플래그는 pseudo-tty를 할당하고 stdin을 열린 상태로 유지하여 컨테이너와 상호작용할 수 있도록 함.Dockerfile
에 지정된WORKDIR
디렉터리(/app)에서 bash가 실행된 것을 확인할 수 있음. 그럼 이제 디버깅할 컨테이너 내에서 대화형 셸세션을 사용할 수 있음.
사진첨부
- 디렉터리 확인
ls
- Bash 세션 종료
exit
사진첨부
- Docker inspect를 통해 Docker에서 컨테이너의 메타데이터를 검토할 수 있음.
docker inspect [container_id]
사진첨부
--format
을 사용하여 반환된 JSON의 특정 필드를 검사함.
docker inspect --format='' [container_id]
사진첨부
작업 05. 게시
- 이미지를
Google Artifact Registry
로 푸시함. - 모든 컨테이너와 이미지를 삭제하여 새로운 환경을 시뮬레이션하고 컨테이너를 가져와서 실행함.
- 이를 통해 Docker 컨테이너의 이식성을 확인할 수 있음.
- Artifact Registry에서 호스팅하는 비공개 레지스트리에 이미지를 푸기하려면 이미지에 레지스트리 이름으로 태그를 지정해야 함. 형식은
<regional-repository>-docker.pkg.dev/my-project/my-repo/my-image
임.
대상 Docker 저장소 만들기
- 이미지를 푸시하려면 먼저 저장소를 만들어야 함.
- 이미지를 푸시해도 저장소 만들기가 트리거되지 않으며 Cloud Build 서비스 계정에는 저장소를 만들 권히 없다.
타색 메뉴
의 CI/CD에서Artifact Registry > 저장소
로 이동하기
사진첨부
저장소 만들기
클릭.
사진첨부
- 저장소 이름 :
my-respository
- 형식 :
Docker
- 위치 유형 - 리전 :
us-central1 (Iowa)
만들기
클릭.
사진첨부
사진첨부
잘 만들어진 것을 확인할 수 있다.
인증 구성하기
- 이미지를 푸시하거자 가져오려면 먼저 Docker가 Artifact Registry에 대한 요청을 인증하는데 Google Cloud CLI를 사용하도록 구성해야 함.
- us-central1 리전의 Docker 저장소에 인증을 설정하려면 Cloud Shell에서 다음 명령어를 실행함.
gcloud auth configure-docker us-central1-docker.pkg.dev
- 메시지가 표시되면
Y
를 입력.
- 이 명령어는 Docker 구성을 업데이트함.
- 이제 Google Cloud 프로젝트의 Artifact Registry와 연결하여 이미지를 푸시하고 가져올 수 있음.
사진첨부
컨테이너를 Artifact Registry로 푸시하기
- 프로젝트 ID를 설정하고 Dockerfile이 포함된 디렉터리로 변경한다.
export PROJECT_ID=$(gcloud config get-value project)
cd ~/test
사진첨부
node-app:0.2
에 태그를 지정하기
docker build -t us-central1-docker.pkg.dev/$PROJECT_ID/my-repository/node-app:0.2 .
- 빌드된 Docker 이미지를 확인하기
docker images
사진첨부
- 이 이미지를 Artifact Registry로 푸시하기
docker push us-central1-docker.pkg.dev/$PROJECT_ID/my-repository/node-app:0.2
사진첨부
시간이 조금 걸린다.
사진첨부
빌드가 완료가 된 것을 확인할 수 있다.
탐색 메뉴
의 CI/CD에서Artifact Registry > 저장소
로 이동한다.my-repository
를 클릭하면node-app
Docker 컨테이너가 생성된 것을 볼 수 있다.
사진첨부
이미지 테스트하기
- 새로운 VM을 시작하고 SSH로 새 VM에 접속한 다음 gcloud를 설치할 수도 있지만 여기서는 간단하게 모든 컨테이너와 이미지를 삭제하여 새로운 환경을 시뮬레이션할 것이다.
- 모든 컨테이너를 중지하고 삭제한다.
docker stop $(docker ps -q)
docker rm $(docker ps -aq)
사진첨부
- 노드 이미지를 삭제하기 전에 (
node:lts
의) 하위 이미지를 삭제헤야 한다.
- 모든 Docker 이미지를 삭제한다.
docker rmi us-central1-docker.pkg.dev/$PROJECT_ID/my-repository/node-app:0.2
docker rmi node:lts
docker rmi -f $(docker images -aq) # remove remaining images
docker images
- 이제 새로운 환경이나 다름 없다.
- 이미지를 가져와서 실행한다.
docker pull us-central1-docker.pkg.dev/$PROJECT_ID/my-repository/node-app:0.2
docker run -p 4000:80 -d us-central1-docker.pkg.dev/$PROJECT_ID/my-repository/node-app:0.2
curl http://localhost:4000
- 결과)
Welcome to Cloud