Docker를 내 수준에서 사용할 때 필요한 간단한 지식을 정리한다.
내가 궁금한 것을 찾아봐 정리한다.
간단한 사용법(CLI)를 정리한다.
공식 document가 되게 친절하더라
Docker에 대해 알아본다. 모든 분야가 항상 오버헤드를 줄이고, 무언가를 빠르게 효율적으로 하기 위한 수단을 찾으려고 노력하는 것 같다. 컨테이너의 개념도 같은 맥락에서 등장했다.
지금 세대가 가꿔나가는 인프라 위에서 다음 세대는 또 어떤 부분에 집중해나갈지 궁금해진다.
특정 기능을 수행하는 큰 프로그램을 만들기 위해 여러 프로그램(DB, 웹서버)등을 설치해야할 때가 있다. 다만 이러한 과정은 예상치 못하는 오류를 자주 보이기도 하며, 상당히 번거롭다. 특정 운영체제나 환경에서 그냥 잘!! 돌아가도록 미리 만들어두고 서로 통신하며 굴러가면 참 좋을 것이다.
그러나 이를 위해 하드웨어를 직접 여러대 장만하는 것은 비용 소모가 크다. 여기서 컴퓨터 안의 컴퓨터인 가상머신의 개념이 나왔다. 운영체제 위에 서로 다른 환경과 운영체제를 각각 구축하는 것이다. 하드웨어 비용 절감은 되지만, 안그래도 용량이 큰 운영체제를 그 때 그 때 설치하는 것도 굉장히 비용 소모적인 일이고, 일단 느리다.
컨테이너의 개념이 등장한다. 각각의 소프트웨어/앱은 하나의 운영체제 위에서 ‘격리된 환경’을 갖고, 그 위에서 실행된다. 이 각각의 격리된 환경을 컨테이너라고 한다. 각각의 컨테이너에는 운영체제 전체가 설치된 것이 아니고, 앱을 위한 파일들(라이브러리 등)만 설치되어있다.
이런 컨테이너 기술을 사용하는 다양한 소프트웨어가 있고, 그 중 docker가 가장 많이 쓰인다.
먼저 CLI 두들겨보고 나서 어떤 개념들이 필요한지 확인하고 다시 찾아 정리했다.
REST API를 사용한다길래 내가 아는 그 http rest api가 맞나? 싶었다. 찾아보니 맞더라..
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": []
},
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]
cat > Dockerfile <<EOF
# 공식 노드 런타임을 상위 이미지로 사용합니다.
FROM node:6
# 컨테이너의 작업 디렉토리를 /app으로 설정합니다.
WORKDIR /app
# 현재 디렉토리 내용을 /app에 있는 컨테이너에 복사합니다.
ADD . /app
# 컨테이너의 포트 80을 외부에 공개합니다.
EXPOSE 80
# 컨테이너가 시작될 때 노드를 사용하여 app.js를 실행합니다.
CMD ["node", "app.js"]
EOF
이 외에도 명령어들이 더 있다.
app.js 파일 생성 후
docker build -t node-app:0.1 .
docker images
를 찍어보면 node, node-app이 모두 보인다. node를 제거하기 위해서는 node-app을 제거해야한다. node:slim, node:alpine과 같은 노드 이미지 등을 사용하면 더 작은 이미지를 제공하기에 이식성을 높일 수 있다.// 실행
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
docker run -p 4000:80 --name my-app
-v [Host파일시스템]:[컨테이너파일시스템]
node-app:0.1
위에서 만들었던 app.js를 수정하고, 다시 image를 build해보자
docker build -t node-app:0.2 .
실행해보면 2단계에서 기존 cache 레이어를 사용하고 있음을 알 수 있다. app.js를 변경했기에 3단계 이후부터만 레이어가 수정된다.
1, 2)와 같은 방법으로 빌드, 실행하면 된다.
// 로그 확인
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가 실행된 것을 확인할 수 있다.docker exec -it [container_id] /bin/bash
와 같이 실행시킬 숫도 있다.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]
# pull
docker pull [hub_account]/[hub_repository]
docker pull gcr.io/[project-id]/node-app:0.2
# 실행 및 확인
docker run ..해당이미지..
curl http://localhost:...