[4차시/15기 최경석] Docker-1
1. Introduction
Docker Overview
왜 docker가 필요한가?
서비스를 개발할때 필요한 다양한 웹서버, db 등등에 대해서, 상호간의 호환성 문제(library, os버전, 등)를 해결하기 위해
→ 모두가 같은 OS, VM 상에서 작동하지만, 각각은 별도의 container 내에 구축된 환경에서 작동
Container은 무엇인가?
Container은 같은 os kernel를 공유하는 완전히 독립된 envorionment
→ 독립된 process, network, mounts,,,
Container개념 자체는 최근에 등장한 것은 아님
- LXC, LXD, LXCFS 등등
Docker는 LXC Container를 활용 → Container를 구축하는건 굉장히 low level에서 이루어지기 때문에, Docker를 통해서 high level에서 다양한 기능을 적용하여 구축할 수 있음
그럼 OS(Operating System)을 알아보자
ex) Ubuntu, Fedora, Suse,,,
모든 Operating System들은 2가지로 구성되어있는데
- OS Kernel
- 실제 하드웨어와 interact하는 부분 (Linux,,)
- Software
- 개발자 도구, 각 OS를 구분, UI,,,
위에서 말했지만, docker의 container은 같은 OS Kernel을 공유한다고 했음
즉, Ubuntu기반의 OS는 Linux Kernel을 사용하기 때문에, Linux기반의 다른 OS (Ubuntu, Fedora, Suse,,,) 기반의 Container를 활용할 수 있
그럼 Container가 Virtual Machine과 다른 점이 뭔가요?
Container은 같은 OS를 공유하고, 그 위에 Docker, Container를 구성
But, VM은 각 VM마다 독립된 OS를 사용
VM은 별도의 OS를 구성하기 때문에 활용도는 높을 수 있지만, 그만큼 메모리를 엄청나게 많이 잡아먹음
VM을 구성해놓고 그 안에 Docker를 사용하는 식으로 구성을 할 수 있음
Container VS Image
- Docker Image
- Application을 포장하고 전송할때 사용
- Image는 application 실행에 필요한 독립적인 환경 및 런타임 환경을 위한 템플릿 (문서)
- 읽기 전용 파일이고, 특정 시점에서 application이 가지는 가지는 속성에 대한 정보를 담고 있음 ⇒ 개발자가 안정적이고 균일한 조건에서 소프트웨어를 테스트할 수 있도록 도와줌
- Image는 템플릿 그 자체이기 때문에 실행할 수는 없음
- 하나의 base image에 대해서, 컨테이너를 실행하면 해당하는 Image를 수정할 수 있는 복사본이 생성되고, 그 위에서 수정을 하고 저장할 수 있음
- 이렇게 수정되고 저장되는 Image는 무제한으로 생성할 수 있고, 초기 상태를 변경하고 저장할 때마다 추가 레이어가 쌓인 템플릿으로 저장됨
- 따라서 image는 여러개의 layer로 구성되고, 각 layer는 이전 단계의 layer의 변형된 형
- Docker Container
- Container는 실행중인 Image의 instance
- 독립적이고, 자신만의 환경을 구축하고 있는 것
- 한개의 image로부터 무수히 많은 container를 생성할 수 있음
기존 개발환경에서는 개발자가 개발을 하면, 그에 필요한 개발 환경이나 라이브러리 등등에 대한 가이드를 보내줘야하는데, 이러면 운영팀에서는 어려움이 많음
⇒ Docker Image의 형태로 전송을 하면 그대로 실행하면 됨!!
2. Docker Command
# Run Command => Container 실행
# 해당 Image가 없으면 docker hub에서 Pull
docker run nginx
# ps Command => 실행중인 container들의 list 및 정보
# random한 ID 부
docker ps
# 실행 중인 container + 이전에 실행했던 container까지 보려면 ps -a
docker ps -a
# STOP => 실행중인 container 중
docker stop """
# Rm => container 삭제
docker rm """
# images => image들의 list (TAG, ID, Size)
docker images
# rmi => image 삭제
# image를 삭제하기 이전에, 해당 image로 생성된 container 들을 먼저 중단하고 삭제해야
docker rmi nginx
# pull => image 저장 (실행은 안함)
docker pull nginx
Container는 특정한 목적(웹서버, db, 연산, 분석 등) 을 위해 불러오는 것이기 때문에!!!
Container를 실행한 뒤에, 유지시키기 위해서는 그 안의 process가 실행이 되어야함
즉, 단순히 불러오고 실행한다고 해서 유지되는게 아님
그래서 ubuntu image를 불러오면, ubuntu는 다른 application을 위한 operating system의 한 종류라서, 생성하면 바로 중단됨
docker run ubuntu
# 5초동안 유지 (sleep 5)
docker run ubuntu sleep 5
# 실행중인 container를 중단하고 싶으면
docker exec '이름'
# attach
# 기본적으로 실행을 하면, foreground에서 실행될거임
# attached to the console??? => 해당 container가 중단될때까지 콘솔에서 다른 행동을 할 수 없음
docker run kodekloud/simple-webapp
# detach (-d)
# container가 background에서 실행 => 프롬프트에서 다른 행동을 할 수 있음
docker run -d kodekloud/simple-webapp
# attach
# detach인 상태에서 다시 attach 하고 싶을 경우
docker attach '이름'
3. Docker Run
# 버전을 설정하고 싶은 경우 => ":version" 적어줌 (tag)
# default는 Latest
docker run redis
docker run redis:4.0
버전 찾는 법 ⇒ Docker Hub에 가면 다 나와있
Docker Hub Container Image Library | App Containerization
docker에서 container를 실행하면, input을 받지 않고 그냥 실행시켜버림
즉, input을 받을 terminal이 없음 ⇒ 그럼 input을 넣고 싶으면 어떻게 하는가??
# 기존
docker run kodekloud/simple-propmp-docker
# input을 넣을 수 있는 형태 (interactive)
docker run -i kodekloud/simple-propmp-docker
# 그렇다 하더라도 아직 terminal의 형태는 없음 => terminal이 있는 형태
docker run -it kodekloud/simple-propmp-docker
PORT Mapping
Docker에서 application을 실행하면, 어떤 서버 위에서 작동하고 있음을 알고 있음
- docker에서 돌아가는 application이 어떤 포트번호를 사용하는지 알 수 있음
- 그럼 어떤 IP를 사용하나?
- 1)Docker Container의 IP ⇒ Internal IP이기 때문에 외부에서 접속할 수가 없음
-
- Docker Host의 IP ⇒ 그러기 위해서는 Container의 포트번호를 사용자가 접속하는 Docker Host의 포트번호에 Mapping 함
# 기존
docker run kodekloud/webapp
# Port Mapping
# Docker Container의 포트번호 5000 -> Docker Host의 포트번호 80
# 원하는 만큼 매핑 시킬 수 있고, 당연하게도 같은 포트번호에 매핑할 수는 없
docker run -p 80:5000 kodekloud/webapp
Volume Mapping
Docker Host안에 Container에 자체 DB가 있는데, 해당 DB의 내용을 Host상에 저장하고 싶을 경우
⇒ 저장을 안해놓으면 Container를 지울때 모든 정보도 같이 삭제 ⇒ 그러니깐, container가 아니라 host 상에서 저장하자
# mysql이라는 Container실행
docker run mysql
# mysql 중단 및 삭제 => 이 경우 모든 정보가 다 삭삭제
docker stop mysql
docker rm mysql
# /var/lib/mysql에 있는 db를 Container 바깥의 /opt/datadir에 Mapping
docker run -v /opt/datadir:/var/lib/mysql mysql
이렇게 해서 Container 를 실행시키면, 외부 경로에 있는 폴더를 불러올 것
Inspect Container
# Inspect : Container에 대한 정보를 JSON파일로 전달
docker inspect '이름'
Container Logs
# Background에서 실행시킨 container의 log 기
docker logs '이름'
4. Docker Image
Docker Image 만들기
Docker image를 왜 직접 만들지??
→ 내가 원하는 서비스가 제공이 안될 때 / 효율적일 때
- Dockerfile 작성 ⇒ “build”
- Local에서 Image 생성 ⇒ “push” Public Docker Hub로 공개
- 1번부터 6번까지 Layer로 순차적으로 생성되며, 처음에 있는 Image에서 필요한 기능들이 layer마다 추가된 것
Docker File
- Dockerfile은 docker가 이해할 수 있는 구체적인 형식(Instruction - Argument)을 가지고 있는 TextFile
- FROM Ubuntu : base OS 가 무엇인지
- RUN : Install 해야 할 사항
- COPY : 해당 경로로 필요한 소스코드를 복사
- ENTRY : 해당 image가 container로써 작동할 때에 사용될 command
- Layer이 추가될때마다 모두 저장되기 때문에, 새로운 layer를 추가하거나 실패했을 때 처음부터 쌓을 필요가 없음 ⇒ 이전 단계에서의 Layer에서 바뀌는 부분만 추가하면 됨
# base image (ubuntu) 생성
# interaction & terminal
docker run -it ubuntu bash
# Python
apt -get update
apt -get install -y python
# Flask
apt -get install pip
pip install flask
# image로 만들고자 하는 source code 저장
# opt/app.py 에 코드 저장
cat > /opt/app.py
# Flask application 시작
FLASK_APP = app.py flask run --host=0.0.0.0
# 실제 서버 확인은 DOCKER HOST에서 Container IP 주소 & 포트번호 를 통해 들어가야함
# Containerize하기 위해서는 우선 전체 step을 확인해야함
# history => 지금까지 어떤 step을 거쳐왔는지 확인
history
# 위에서 확인한 history를 containerize하려면 일단 docker file을 만들어야함
mkdir my-simple-webapp
cd my-simple-webapp
# docker file 생성
cat > Dockerfile
FROM ubuntu
RUN apt-get update
RUN apt-get install -y python python-pip
RUN pip install flask
COPY app.py /opt/app.py
ENTRYPOINT FLASK_APP = app.py flask run --host=0.0.0.0
# app.py가 local에 없으므로 만들어줌
# docker image 생성!!
# image 이름은 tag 로 생성 "my-simple-webapp"
docker build . -t my-simple-webapp
# 모든 과정을 저장하기 때문에 처음부터 다 만들필요 없음
# public으로 공개하기 (로그인 해야함)
docker push 이름/파일이름
환경변수 : Environment Variables
매번 소스코드를 일일이 바꿀 수 없으니, environment variable 로 둬서 편하게 바꾸자!
docker run simple-webapp-color
docker run -e APP_COLOR=blue simple-webapp-color
# 환경 변수는 어떻게 찾나?? inspect -> Config -> Env
docker inspect """"
Command & Entrypoint
Container은 해당 process가 지속될 동안에만 유지됨
멈추거나 완료되면 container에서 exit함!!
CDM(Command) : Container 내에서 어떤 process가 진행될 것인지 정의
다른 command를 사용하고 싶다면?
- 실행할 때에, 다른 command를 기본 command위에 덮어씀
# 기존 command를 override
# sleep 5 : command
docker run ubuntu sleep 5
# 이걸 고정하고싶으면 새로운 image 생성
# CDM ["command", "param"]의 형태로 생성
FROM Ubuntu
CMD sleep 5
CMD ["sleep", "5"]
# 생성
docker build -t ubuntu-sleeper .
# 이걸 또 다시 10초로 늘리고 싶다??
docker run ubuntu-sleeper sleep 10
# 이렇게 하면 너무 이상함
docker run ubuntu-sleeper 10
# 이렇게 만들고 싶으면 어떻게 하지?? => 이건 Entrypoint 덕분
FROM Ubuntu
ENTRYPOINT ["sleep"] sleep 10
# 라고 하면 뒤에 10만 붙이면 sleep 10 으로 설정됨
# 만약 entrypoint만 설정하고 cmd 없이 그냥 run 할 경우?
docker run ubuntu-sleeper
#라고 하면 에러가 발생함 (operand가 없으므로)
# 이걸 해결하려면 둘 다 사용하는거임!!
FROM Ubuntu
ENTRYPOINT ["sleep"]
CMD ["5"]
# entrypoint도 바꾸고 싶으면 (sleep -> sleep2.0)
docker run --entrypoint sleep2.0 ubuntu-sleeper 10