udemy Docker for the Absolute Beginner 강의 내용 정리
- LXC
- LXD
- LXCFS
Docker는 LXC 컨테이너세팅을 사용. 이 컨테이너를 세팅하는건 엄청 low level이라서 어렵다. 그래서 docker가 tool을 제공해.
Docker는 OS위에 올라가. Linux중에서 ubuntu는 그냥 쓸수있고, fedra 등 다른 애들은 추가 application이 필요함.
windows에서는 docker container를 실행시키지 못해. windows는 Linux virtual machine에서 linux container를 실행시키는거야.
- 하드웨어 + Hypervisor
- Hypervisor 위에 VM을 띄움.
- VM은 OS + Libs + Deps + App
- GB단위로 무거움
- 하드웨어 + OS + Docker + container
- container는 Libs + Deps + App
- MB단위. 빠름.
- docker image: package, teamplate, plan
- container: image를 실행시킨 instance (하나의 image로 여러 container를 올릴수 있다)
- image로부터 container로 실행시키는데 사용해.
docker run {image name}
docker run nginx
- nginx application instance를 docker host에 올린다.
- docker 없으면 hub에서 받아오고, 있으면 재사용함.
- 특정 name으로 container를 올리고 싶으면
docker run --name {container name} {image name}
- 특정 버전의 image를 사용하고 싶으면
docker run {image name}:{image version}
(image version의 default는latest
)
docker hub에서 다운받을때
docker hub에서 ubuntu를 검색하면 여러가지 버전을 볼 수 있는데,
Supported tags and respective Dockerfile links
18.04, bionic-20210118, bionic
20.04, focal-20210119, focal, latest
20.10, groovy-20210115, groovy, rolling
첫번째 라인에서 bionic이라고 써도 18.04 버전을 다운받을 수 있다. (alias처럼 사용 가능)
docker run ubuntu:bionic
docker ps
- container list를 받아옴. 기본정보( id, name)가 보여져.
docker ps -a
: stop시킨것까지 보임
docker stop {container name}
- stop
docker rm {container name}
- 완전 지움
docker images
- show image list
docker rmi {image name}
docker rmi nginx
- 해당이미지로 run중인 container가 없는지 확인하고지워야해. (그냥 지우면 에러남ㅋㅋ)
docker pull nginx
- download받지않고 잠깐 사용해보고싶을때 사용.
docker run ubuntu
를 하고 docker ps를 하면 아무것도안나와.docker ps -a
하면 끝났다고 나와.왜?
- ubuntu는 os이미지기때문에 이미돌고있기때문에 시작하자마자 stop돼.
docker run ubuntu sleep 5
: 5초 후에 run (docker ps로 확인가능)
docker exec {container name} {commands}
docker exec distracted_mcclintock cat /etc/hosts
: distracted_mcclintock container의 /etc/hosts파일 확인
docker로 웹서버에 붙으려면?
docker run kodeloud/simple-webapp
- 8080포트로 붙어. 실행시킨동안 command는 아무것도 못치거든? background로 실행시키려면
docker run -d kodeloud/simple-webapp
하면돼.
- hub.docker.com에서 official image는 다운받을때 library/~에서 받아옴 (library/centos)
- docker run -it centos bash 라고하면 centos image안에서 bash로 붙을수있어
- docker run kodekloud/simple-propt-docker 하면 output만 출력됨.
-i
(interactive)추가:docker run -i kodekloud/simple-propt-docker
: standard input 입력 가능-t
(psueod terminal)추가:docker run -it kodekloud/simple-propt-docker
: terminal로 container에 붙을수 있어
webapp을 container로 띄울때를 생각해봐. docker run kodekloud/webapp
-
docker host로 임의의 internal IP가 할당돼. 근데 이건 interanl IP이고, container로 붙을때는 docker host IP인 192.168.1.5:80 과 같은 IP, port로 붙어야해. 그럼 80 port가 5000번을 가리키도록 해야겠지?
-
docker run -p 80:5000 kodekloud/webapp
이렇게 docker를 띄워서 붙으면돼. (application은 5000으로 listen하고있고 나는 80으로 뚫겠다)
docker run -p {host port}:{container port} kodekloud/webapp
-
instance가 여러개일 경우 아래와 같이 띄우면 돼.
docker run -p 8000:5000 kodekloud/webapp
(application은 5000으로 listen하고있고 host에서는 8080 뚫겠다)
docker run -p 8001:5000 kodekloud/webapp
(application은 5000으로 listen하고있고 host에서는 8081 뚫겠다) -
image name은 항상 맨뒤에 와야해! (
docker run kodekloud/webapp -p 8000:5000
하면 port mapping 안먹힘) -
internal IP는
docker inspect {container_id}
로 알아낼 수 있다."Networks":{ "bridge":{ "IPAddress": "이걸 보면돼" } }
-
PORT mapping 해야 browser에서 저 IP+새로운 포트로 붙을수 있다.
- mysql container를 지우면 어떻게 될까?(
docker stop mysql
->docker rm mysql
) 데이터가 다 날아가버려 ㅠㅠ docker run -v /opt/datadir:/var/lib/mysql mysql
: (바깥 경로에)/opt/datadir 라는 디렉토리를 만들어서 (container 내 경로인)/var/lib/mysql을 매핑시키겠다. (매핑된 바깥경로에 mount되어 mysql container를 지워도 데이터는 남아있게된다.)
권한 에러가 나면?
- -u root 옵션을 추가한다. (-u: user)
docker run -v /var/my-jenkins-data:/var/jenkins_home -u root jenkins
docker inspect blissful_hopper
: container정보를 JSON format으로 볼수있다. (state, mounts, configuration data, network, setting 등)
docker logs blissful_hopper
-
docker run ubuntu sleep 15
하면 foreground에서 돌고있기때문에 15초간 ctrl+C나 ctrl+Z로 끝낼수 없다. 새로운 세션을 열어서 stop명령어를 통해 프로세스 종료해야해. -
docker run -d ubuntu sleep 100
하면 background로 돌릴수있다. 그러면 output으로 나오는게 container id인데(docker ps
로도 알 수 있다),docker attach {container_id}
를 실행시키면 foreground에서 돌도록 변경할 수 있다. -
background로 돌리는걸 detach(-d option), foreground에서 도는걸 attach라고 해.
docker run timer
: 무제한으로 타이머가 돌아.
- 명령어를 쭉 적어놓은 script야..
- 각 line은 [instruction] [argument] 로 적어
- instruction은
FROM
,RUN
,COPY
같은애들.. - 모든 dockerfile은 base OS명 또는 다른 이미지로 시작해야해. e.g.)
FROM Ubuntu
- 제일 마지막 라인은
ENTRYPOINT
를 사용해서 작성해. 만약 실제로 python app.py 라고 실행해야하면ENTRYPOINT ["python", "app.py"]
라고 작성하면 돼
docker build .
docker build . -f Dockerfile -t mmumshad/my-custom-app
(-t옵션은 tag를 단다는 뜻)- build를 하는 순간 각 line들은 layer1, layer2, layer3... 이렇게 생성돼.
- 각 layer들은 바로 이전 layer에서 변경된 size만 저장한다.
- dockerfile을 수정해도 이전 데이터들을 caching해놓기 때문에 rebuilding하는건 빠르다. (update된 layer의 바로 위의 layer만 rebuild된다)
docker run mmumshad/my-custom-app
docker push mmumshad/my-custom-app
-
docker build .
를 한 후docker push my-custom-app
를 하면 permission denied error가 떠. 왜냐면 공식 library/에 올리려고 하기때문에.. 그래서mmumshad/
와 같이 본인 계정을 명시해줘야하는데,docker build . -t mmumshad/my-custom-app
이렇게 새로 빌드를 해서 새로운 이미지를 만든 후 push해야함 -
push 하기전에
docker login
명령어를 통해서 로그인도 해야함.
-
conf.json같은 설정.
-
code를 변경하지않고 설정만 변경해서 container를 띄우겠다.
e.g) 코드에는os.environ.get('APP_COLOR')
와 같이 쓰고 실행시키는 시점에 아래와 같이 env값을 넘겨줄 수 있다.docker run -e APP_COLOR=blue simple-webpp-color docker run -e APP_COLOR=pink simple-webpp-color
-
docker inspect blissful_hopper
[ { (...) "Config": { "Env": [ "APP_COLOR=blue", //here! "LANG=C.UDF-8", "...." ] } } ]
- container는 모든 OS system을 뜻하는게 아냐.
- container는 특정 task 또는 process를 의미하는거. (web server instance의 host나 application server, database 등등)
- task가 complete되면 container는 끝내. container는 그 안에 process가 살아있을때만 살아있거든.
(그래서 container에 있는 webserver process가 crash나서 꺼지면 container도 끝나.)
- NGINX같은 Docker image를 보면 instruction을 볼수있어.
CMD
라는 instruction 뒤에 나오는 argument를 보면돼. (CMD ["nginx"]
)
방법 1. 그냥 쭉 작성
docker run ubuntu sleep 5
방법 2. image 작성한후 이미지 실행
FROM Ubuntu
CMD sleep 5
CMD
는CMD command param1
또는CMD ["command", "param1"]
과 같이 쓸수있어. (첫번째 element는 executable해야해)
docker build -t ubuntu-sleeper .
docker run ubuntu-sleeper
FROM Ubuntu
CMD sleep 5
docker run ubuntu-sleeper sleep 10
으로 실행시키면돼.
아래와 같이 변경하면
FROM Ubuntu
ENTRYPOINT ["sleep"]
docker run ubuntu-sleeper 100
로 실행시키면돼. (sleep빼고)
CMD
instruction: command line parameter는 전체 명령어를 다 전달해줘야하고
ENTRYPOINT
는 작성한 명령어에다 run할때 넘긴 parameter가 append돼서 실행된다.
ENTRYPOINT에서 parameter값을 넘기지않고 실행시키면.. (docker run ubuntu-sleeper
) sleep argument가 없다고 에러가나. 그럼 default값을 어떻게 주면 될까?
FROM Ubuntu
ENTRYPOINT ["sleep"]
CMD ["5"]
docker run ubuntu-sleeper
-> sleep 5
docker run ubuntu-sleeper 10
-> sleep 10 (overriding)
entrypoint값인 sleep을 overriding할수도 있어.
docker run --entrypoint sleep2.0 ubuntu-sleeper 10
-> sleep2.0 10 (overriding)
-
docker-compose.yml
파일을 작성해서docker-compose up
을 수행하면된다.docker-compose.yml
services: web: image: "mmumshad/simple-webapp" database: image: "mongodb" messaging: image: "redis:alpine"
-
여러가지 서비스를 올릴때 dependency가 있는애들끼리는 서로 link를 해줘야해.
WAS - Redis - worker - db 와 같은 구조에서는 WAS service와 redis service를 link를 해줘야 해
docker run -d --name=redis redis
docker run -d --name=vote -p 5000:80 voting-app
->docker run -d --name=vote -p 5000:80 --link redis:redis voting-app
-
사실 --link 이렇게 하는건 deprecated되었지만 기본적인 개념이해를 위해서 설명해줌.
(docker-compose.yml
에다links
로 작성하면됨)docker-compose.yml with links
redis: image: redis db: image: postgres:9.4 vote: image: voting-app ports: - 5000:80 links: - redis result: image: result-app ports: - 5001:80 links: - db worker: image: worker links: - redis - db
- redis, postgres는 official image
- voting-app은 직접 만든건데, image대신 build할 code path를 입력해주면 compose up하는 시점에 image build를 하여 사용할 수 있다.
image: voting-app
->build: ./vote
-
docker compose file은 version1, version2, version3 등 다양한 버전이있어.
-
docker-compose.yml
파일 맨 위에 version을 명시해서 무슨버전의 docker compose file인지 명시해야해. -
version1 -> version2로 가면서
- 그냥 쭈루룩 서비스썼다면, services: 아래에 서비스를 적어야해.
- networking: (links를 안써) v1에서는 모든 container를 default bridge network에서 돌리고, 서로 communication하기위해서 link라는걸 사용했어. v2에서 docker compose는 자동으로 application별로 dedicated bridge network를 구성하고, 모든 container들을 서로의 service name으로 통신해.
- redis service가 실행된 후 vote service가 실행되어야 한다는걸 depends_on으로 명시해줘.
-
version2 -> version3
- version3는 Docker Swarm이라는 애가 지원하는거야.
- depends_on도 없어. 자세한건 뒤에서 더 설명한대~~
docker-compose.yml (ver.2)
version: 2 services: redis: image: redis networks: - back-end db: image: postgres:9.4 networks: - back-end vote: image: voting-app ports: - 5000:80 depends_on: - redis networks: - front-end - back-end result: image: result-app ports: - 5001:80 networks: - front-end - back-end worker: image: worke networks: front-end: back-end:
- vote, result는 was라서 frontend, backend network값을 모두 지정하고, redis랑 db는 backend만 지정.
-
DB 접속 에러나면(Database is uninitialized and superuser password is not specified) POSTGRES_PASSWORD 명시해줘야함.
db: image: postgres:9.4 environment: POSTGRES_USER: potgres POSTGRES_PASSWORD: potgres networks: - back-end
-
docker-compose.yml 파일 작성할때 3.0은 또 string으로 써야하는가봐
version: "3.0"
-
image: nginx
라고 하는건image:nginx/nginx
와 같아.
image: {user account}/{image repository}
image: {registry}/{user account}/{image repository}image: docker.io/nginx/nginx
$ docker login private-registry.io
$ docker run private-registry.io/apps/internal-app
$ docker run -d -p 5000:5000 --name registry registry:2
$ docker image tag my-image localhost:5000/my-image
$ docker push localhost:5000/my-image
$ docker pull localhost:5000/my-image
$ docker pull 192.168.56.100:5000/my-image
-
docker를 linux에 설치를하면 실제로 3개가 설치돼. Docker CLI, REST API, Docker Daemon
-
Docker daemon: docker object(image, container, volumne, network같은)를 관리해
-
Docker Rest API server: daemon이랑 통신하기위해 만든 인터페이스.
-
Docker CLI: command line interface
- Docker CLI는 daemon이랑 api server랑 같은 host에 있을 필요가없어.
- laptop같은데 cli만 설치해서 사용할 수 있어.
docker -H=remote-docker-engine:2375
docker -H=remote-docker-engine:2375 run nginx
"docker는 workspace를 분리하기위해서 namespace 라는걸 사용해."
그래서 Network, PID, Mount, InterProcess, Unix Timeshareing system들이 container에서 서로 분리돼있어.
- Linux System에서 Container가 Child System으로 들어가 있는 경우 Child system의 PID는 1부터 다시 시작한다.
- Child system의 PID:1 process는 host system의 PID:7과 같이 매핑된다.
- CPU나 Memory도 같이 공유해.
- default로는 사용할수있는 resource에 제한이 없어.
- host cpu의 50%만 사용하게 하고싶다면
docker run --cpu=.5 ubuntu
- host memory의 100MB만 사용하게 하고싶다면
docker run --memory=100m ubuntu
- 추가 명령어 링크
$ docker exec 5a5f912e0f0e ps -eaf # docker container(5a5f912e0f0e)에서 실행되는 모든 ps list반환
# PID: 1 인 process가 뜰거야
$ ps -eaf | grep docker-java-home # docker container안에서 PID:1이던 애를 host에서 grep해서 확인.
# PID: 27700 과 같이 다른 값이 뜸
- docker를 설치하면 /var/lib/docker 폴더가 생서오대. (image, container, volumn같은애들이 저장됨)
- Docker Layered architecture를 이해해야해.
- layer가 같으면 새로 받아오지않아.
- layer1()+layer2(apt package)+layer3(pip package. dependency들)+layer4(source code)+layer5(entrypoint)
- 위 내용들이 docker image layer야. build 를 하고나서부터는 readonly야. 고칠수없어.
docker run maisy/my-custom-app
과 같이 실행을 하면 writable한 layer가 layer6으로 올라가. [Container Layer]- 같은 image layer는 여러 container들사이에서 공유가 돼.
- image layer의 내용을 conatainer안에서 overwrite 해서 수정할 수 있어. => COPY-ON-WRITE 매커니즘
$ docker volume create data_volume
- 명령어를 수행하면
/var/lib/docker/volumes/data_volume
경로로 폴더가 생성돼
docker run -v data_volume:/var/lib/mysql mysql
- container안의 /var/lib/mysql경로에 data_volume을 생성하겠다.
- mysql에서 쓰는 모든 데이터는 docker host에서 생성한 /var/lib/mysql 경로에 만들어져.
- 여기서 생성한 데이터는 host의 /var/lib/docker/volumes에 mount 된다.
- 이 데이터들은 container가 사라져도 데이터는 남아있게돼.
- docker가 data_volumne2라고 알아서 생성을 하고 /var/lib/docker/volumes 경로에 mount된다.
docker run -v data_volumn2:/var/lib/mysql mysql
을 수행한것과 같다.
- /data라는 경로에 쓰고 싶다면
docker run -v /data/mysql:/var/lib/mysql mysql
이라고 치면 돼. - 이런식으로 host에 있는 어느 경로든지 container내의 volumn과 binding 시킬 수 있어.
docker run --mount type=bind,source=/data/mysql,target=/var/lib/mysql mysql
- AUFS, BTRFS, ZFS, Device Mapper, Overlay, Overlay2
- AUFS는 ubuntu를 사용할때 default strage driver고, fedora나 CentOS같은 OS에서는 AUFS를 지원을 안해.
- fedora, CentOS에서는 Device Mapper가 더 좋아
- docker가 OS에 맞게 알아서 storage driver를 골라.
-
docker info
: docker version, storage driver, root directory 등을 확인할 수 있어 -
/var/lib/docker/aufs/
에 가면 diff, layer, mnt 폴더가 있다. (https://docs.docker.com/storage/storagedriver/aufs-driver/) -
docker hostory {image id}
: image를 어디서 받아온건지, 어떻게 변한건지docker build
를 한다음docker build . -t simple-webapp
(tag를 붙여줌)을 다시하면, 이전 최초 빌드는 5분씩 걸렸는데 얘는 1초만에 돼. (코드가 수정된게 없으니까 cache에 있는 특정 layer에 있는걸 그대로 갖다씀)docker history simple-webapp
을 하면 docker image자 어떻게 빌드됐는지 확인 할 수 있어.
-
docker system df
: docker의 system usage보여줌 -
docker system df -v
: (--verbose): 더 상세하게 보여줌
- container가 붙는 default network (
docker run ubuntu
만 하면 Bridge에 연결) - private internal network
docker run Ubuntu --network=none
docker run Ubuntu --network=host
: run이나 host network에 붙이기- 같은 host에서는 같은 port로 web container를 두개 올릴순 없어.
- none은 isolated container야.
docker network create --driver bridge --subnet 182.18.0.0/16 custom-isolated-network
docker network ls
명령어로 network list(IP, Driver, name)를 모두 볼수 있어.
docker inspect {container id}
: 컨테이너 id로도 network 정보 조회항수있어. (inspect명령어 사용)
- (Networks- host로 되어있으면 host에 붙은거고 bridge로 돼있으면 bridge에 붙은건가봐.)
- Networks - bridge - IPAddress(Internal address), MacAddress
(mysql container가 172.17.0.3으로 떠있을때)
- mysql.connect(172.17.0.3) 으로 해도 되지만 ip는 reboot될때 변경될 수 있어.
- 대신, mysql.connect(mysql) 와 같이 container name을 써주면돼.
- DNS 서버가 mysql: 172.17.0.3라고 관리를 해.
- DNS서버는 항상 127.0.0.11로 뜸.
(bridge driver 사용, subnet은 182.18.0.1/24, gateway는 182.18.0.1)
docker network create --driver bridge --subnet 182.18.0.1/24 --gateway 182.18.0.1 wp-mysql-network
$ docker run --name webapp -p 38080:8080 -e DB_Host=mysql-db --link mysql-db:mysql-db -d --network=wp-mysql-network kodekloud/simple-webapp-mysql
- Oracle VM + Docker engine + Docker machine + Docker compose + Kitematic GUI(UI)
- Oracle VM 대신 Hyper-V 를 사용함.
Windows host에서 linux container를 실행시킬 수 있어.
windows container나 linux container(default)를 선택할수있어.
windows container를 선택해서 windows app을 만들수도 있어.
windows container를 선택하려면 'switch to Windows containers'를 선택해야행
- Windows Server 2016
- Nano Server
- (Hyper-V Isolated Container를 사용하려면) win10 enterprise version이상
- Windows Core: Windows container on native windows server core
- Hyper-V Isolation: Windows container on an isolated hyper-v kernel
- 얘의 container는 kernel isolation까지도 보장해줄수있도록 최적화된 vm이다.
- 같은 windows host에서 동시에 두개를 돌릴수는 없어. (windows core -> hyper-v migration guide는 공홈에 있음)
(linux에서는 Ubuntu, Fedora, Debian등의 base image type이 있듯이) 두개가있다.
- Windows Server Core
- Nano Server: headless deployment option(linux에서 Alpine같은거래)
사용자 수가 늘어서 load가 늘어나면.... docker run nodejs
를 여러개 올려야해
하나에 장애가 생기면.. 또 모니터링하다가 직접 올려줘야하고...
근데 큰 서비스는 1000개넘는 container가 있을수도 있는데.. 어찌해
container orchestration 을 통해서 해결가능!
- multiple docker host
docker service create --replicas=100 nodejs
- docker orchestration solution 종류는 여러가지야. Docker Swarm, kubernetes, MESOS...
- host가 여러개가 있을때
한 host를 Swarm Manager또는 master로 지정을 해줘야해. (다른애들은 worker)
- manager node에서
docker swarm init
수행 - worker node들에서
docker swarm join --token <token>
수행(manager에 붙기위해) - my-web-server를 하나 띄우고 싶을때, manager node에서 아래 명령어 수행(worker node말고!)
docker service create --replicas=3 my-web-server
kubectl run --replicas=1000 my-web-server
: 1000개의 instance 실행kubectl scale --replicas=2000 my-web-server
: instance랑 infrastructure들이 알아서 2000개로 scale up됨.kubectl rolling-update my-web-server --image=web-server:2
: rolling update가능kubectl rolling-update my-web-server --rollback
kubernetes는 docker host를 사용해. 그 docker host는 docker container형태의 application이라고 보면돼.
- 꼭 docker일 필요는 없어. (크라이오(CRI-O)나 rocket? 사용 가능.)
-
node group. 한 노드가 실패하면 다른 노드에 붙으면 돼.
-
master는 worker node들 감시함.
-
k8s를 설치하면 API server, etcd, Scheduler, Controller, Container Runtime(docker engine같은거), kubelet 을 설치해
-
etcd: key-value store. cluster를 관리할수있는 정보들을 저장해.
-
kubelet: 클러스터에서 각 노드들을 run 시켜주는애. container들이 원하는대로 실행되도록 해줌.
kubectl run hello-minikube
kubectl cluster-info
kubectl get nodes
kubectl run my-web-app --image=my-web-app --replicas=100