Isolation
여러 애플리케이션의 논리적인 격리(isolation)를 위해서 여러 VM을 생성하면 비용(CapEx, OpEx)의 증가로 이어짐
Isolation without OS
같은 OS위에서 여러 애플리케이션의 isolation을 제공하는 것이 container
Containers
컨테이너는 하나의 디렉토리에서 수행하는 프로세스와 같다. 모든 라이브러리, 바이너리, 설정 파일이 한 군데 있다.
VM은 마치 물리적인 독립처럼 보이게 하는 논리적인 독립인 것처럼,
- Containers share the machine’s OS system’s kernel and therefore do not require an OS per application.
- A container is a standard unit of software that packages up
- Code
- Dependencies
- but not the OS
VM vs Container
- Containers offer isolation not virtualization
- Containers are OS virtualization
- VMs are hardware virtualization
- VMs need OS
- Containers don’t need OS
- Containers uses host OS for compute resource
참고: https://www.docker.com/resources/what-container/
Docker
Manages your Containers.
Docker는 Container가 아니고, Container는 Docker가 아니다.
Docker manages your containers. So it is called a Container runtime environment.
you can run containers without docker, but then you have to create the whole directory, the dependencies, Cgroup, Namespace, etc. you have to take care of all that yourself.
Therefore we can run Containers by using Docker engine.
What is Docker
Docker Inc. 이라는 회사명
Docker engine : container runtime environment that can manage your container easier
Docker project : is still an open source project (Github)
Docker Engine
A Docker engine is a daemon, a service running in the OS, and can connect it with REST API or the CLI command.
You don’t have to create images from scratch, there are lots of images, and can even customize the images.
오래된 기술이지만 (Docker engine 2013년경 출시) 기존에 이미지가 불편했던 방면 Docker가 불편함을 해결해주었다. → you can just pull the image and run the container from that with simple docker commands.
You can also create your own network.
Docker Containers
Docker containers that run on Docker Engine:
- Standard: Docker created the industry standard for containers, so they could be portable anywhere.
- ⇒ Standard means you can run it on any hardware, any OS, as long as the Docker engine is installed to run the containers.
- Lightweight: Containers share the machine’s OS system kernel and therefore do not require an OS per application, driving higher server efficiencies and reducing server and licensing costs.
- Secure: Applications are safer in containers and Docker provides the strongest default isolation capabilities in the industry
⇒ main reason why we use Dockers → offers isolation without OS
Attaching into the Docker image
How can you log in to the container like a VM, as you do SSH, but there’s no SSH running in the container because it’s just a process, so you can’t really do SSH.
However you can attach to this container, or if you don’t want that you can run commands also on this. There is an option docker exec and give the container name or the ID and then you can run commands.
# docker exec myweb ls
하면 image안의 디렉토리 구조가 보인다.
그러나 attach를 하고 싶으면 다음을 입력
# docker exec -it myweb /bin/bash
-it : i 는 interactive라는 뜻, t는 tty라는 뜻.
그러면 container 안에 들어오게 된다.
(some containers don’t have bash shell → you can type /bin/sh instead)
여기 안에서는 ifconfig나 ps가 안 먹힌다. 그러나 설치 할 수 있다.
debian based container이므로
# apt update
를 할 수 있다.
# apt install procps -y
를 설치하면 ps 커맨드를 사용할 수 있다. ⇒ we are installing and creating data in the container. 이제
# ps -ef
하면 프로세스를 볼 수 있다.
# exit
로 빠져나올 수 있다.
이제 container를 없애고 이미지를 지우려면 순서대로
// 1. stop the container
# docker ps
# docker stop [container id or name]
// 2. remove the container
# docker rm [container id or name]
// 3. delete the image
# docker images
# docker rmi nginx // 같은 이름이 있으면 nginx:[tag name]
Container Volumes
Persisent storage for volatile containers
설정을 바꾸거나 업데이트를 할 때 보통 container에 로그인을 하기보다 지우고 updated image로부터 updated container를 만든다. 그래서 volatile하다. 그러나 stateful한 요소를 원하면 container volume을 붙인다.
Container Data
- The data doesn’t persist when that container no longer exists and it can be difficult to get the data out of the container if another process needs it.
- A container’s writable layer is tightly coupled to the host machine where the container is running. You can’t easily move the data somewhere else.
Docker has two options for containers to store files in the host machine.
- Volumes : it’s a wrapper where in the Docker volumes directory에 새로운 디렉토리를 생성해서 container에 attach한다. 이 디렉토리에 있는 모든 data는 host machine에 있는 volumes로 간다.
- Managed by Docker in : /var/lib/docker/volumes/ on Linux
- Bind Mounts :
- Vagrant의 sync directory와 같은 개념 → where you can take any directory and map it to a container directory.
두 가지 경우를 다 살펴보자.
Bind Mount 예시
MySQL로 예시 → 우선 hub.dockercom에서 mysql 검색.
official docker에 다음과 같이 나온다.
Starting a MySQL instance
$ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
where some-mysql is the name you want to assign to your container,
(위에서 -e 는 export variables 이라는 뜻 - otherwise it won’t run)
my-secret-pw is the password to be set for the MySQL root user and
tag is the tag specifying the MySQL version you want.
Container volume은 공식 문서를 주욱 내리다보면
$ docker run --name some-mysql -v /my/own/datadir:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
/my/own/datadir 은 host machine의 디렉토리
/var/lib/mysql 은 container volume의 디렉토리
위처럼 공식문서에 나오는 경우도 있지만 inspect command를 이용해 어느 디렉토리에 저장하는 지 확인할 수도 있다.
이제 pull image한다.
$ docker pull mysql:5.7
Now i want to know which is the volume directory, or what port number the process runs.
$ docker inspect mysql:5.7
exposed port는 3306과 33060 두 개가 있고,
docker run 할 시 실제 실행되는 부분은 Entrypoint이고, Cmd 부분의 변수가 argument로 docker-entrypoint.sh의 인자로 넘어가 실행이 된다.
"Entrypoint": [
"docker-entrypoint.sh"
]
더 밑으로 내리면
"Volumes": {
"/var/lib/mysql": {}
}
위 위치가 volume.
이제 제일 처음에 문석에 있던 커맨드 입력
$ docker run --name my-db -d -e MYSQL_ROOT_PASSWORD=1234 -p 3030:3306 -v /home/yjkim/temp:/var/lib/mysql -d mysql:5.7
-d : background에서 run 할 수 있게 까먹지 않고 넣는다.
: 콜론 뒤에 container directory
$ docker ps // docker 실행 확인
$ ls temp // volume 확인
$ docker exec -it my-db /bin/bash
로 로그인을 해보면
# cd /var/lib/mysql
# ls
해보면 you have exactly the same data.
이제 container를 지워보자
$ docker stop my-db
$ docker rm my-db
$ ls temp
하면 여전히 data가 그대로 남아있다.
Bind Mount 는 주로 host machine에서 → Container로 데이터를 넣기 위해서 사용된다. 예를들어 소스코드를 host machine에서 쓰고 container에서 받아서 처리할 때.
However, for purpose of preserving data, the better option is Docker Volume.
Docker Volume
$ docker volume create my-db-volume
$ docker run --name my-db -d -e MYSQL_ROOT_PASSWORD=1234 -p 3030:3306 -v my-db-volume:/var/lib/mysql -d mysql:5.7
$ docker ps
$ sudo ls /var/lib/docker/volumes/my-db-volume/_data/
로 volumes 디렉토리에 있는 data가 보인다.
$ docker inspect my-db
하면 port mapping이나 volume의 정보를 볼 수 있다.
ip 주소도 나온다 : 172.17.0.2
mysql을 설치하고 접속할 수 있다.
$ sudo apt install default-mysql-client -y
$ mysql -h 172.17.0.2 -u root -p1234
mysql> show databases;
실습이 끝나면 clean up
$ docker ps -a
$ docker stop my-db
$ docker rm my-db
$ docker rmi mysql:5.7
지워도
$ sudo ls /var/lib/docker/volumes/my-db-volume/_data/
는 남아있다.
Build Images
Dockerfile contains information to build images
We can take an official image → make changes and build our own customized image. (AWS의 AMI처럼)
To build docker images you need to write a Dockerfile.
Dockerfile :
we provide instructions in this file of how to build the image, what should it contain, what packages it should install, what volume to export.
그리고 docker build command을 하면 image를 생성한다.
just like we have pom.xml for Maven which builds the artifact,
here Dockerfile is going to build an image for us.
Dockerfile Instructions
- FROM → base image (like Ubuntu, MySQL, Nginx, an official image will be good for this)
- LABELS → adds meta-data to an image (like tags in EC2)
- RUN → execute commands in a new layer and commit the results
- ADD / COPY → add files and folders into image
- copy : will just take the file and dump it,
- add : with add instruction you can provide a link, an archive so it can download from a link and put it in your image, or can unarchive an archive file
- CMD : runs binaries/commands on docker run
- ENTRYPOINT : similar to CMD but higher priority when you mention both CMD and Entrypoint together. → Entrypoint에 command를 넣고 CMD에 인자를 넣을 수 있다.
- allows you to configure a container that will run as an executable.
- Volume → create a mount point and marks it as holding externally mounted volumes
- Expose → Container listens on the specified network prots at runtime.
- ENV → sets the environment variable
- User → sets the user name (or UID)
- WorkDir → sets the working directory
- ARG → defines a variable that users can pass at build-time
- OnBuild → adds to the image a trigger instruction to be executed at a later time
참고 : https://docs.docker.com/engine/reference/builder/
What is Docker Compose
a tool to run multicontainers together.
when we run multiple containers together we can mangage it centrally.
따로 설치해야한다.
공식 문서 : https://docs.docker.com/compose/
YAML file에 모든 container information이 들어있다.
(what Vagrant is for VMs, Docker Compose is for containers)
공식문서 예제:
- Dockerfile 작성 - so it can be reporduced anywhere
- docker-compose.yml 를 정의 - so they can be run together in an isolated environment.
- docker compose up → starts your entire app
docker-compose.yml 파일은 다은과 같다.
version: "3.9" # optional since v1.27.0
services:
web:
build: .
ports:
- "8000:5000"
volumes:
- .:/code
- logvolume01:/var/log
depends_on:
- redis
redis:
image: redis
volumes:
logvolume01: {}
services는 containers를 뜻함. 위에는 두 가지 container가 있다. web과 redis가 있다.
build: . 는 dot은 docker-compose.yml 파일과 같은 디렉토리에 Dockerfile이 있다는 뜻.
volumes : 에 .:/code는 Bind Mount이고, 가장 마지막 줄의 volumes는 Volume
Installling Docker Compose
공식 문서의 getting started에 좋은 예제가 있지만 그 전에 설치해야한다.
https://docs.docker.com/compose/install/linux/
최신 버전은 여기서 확인 : https://github.com/docker/compose/releases
$ sudo curl -L "<https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$>(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
$ docker-compose -version
Docker
** 도커 이미지와 컨테이너
- 이미지와 컨테이너는 도커에서 사용하는 가장 기본적인 단위로 이미지와 컨테이너는 1:N 관계를 가진다
- 이미지는 컨테이너를 생성할 때 필요한 요소로 컨테이너의 목적에 맞는 바이너리와 의존성이 설치되어있다. (여러개의 계층으로 된 바이너리 파일로 존재)
- 컨테이너는 호스트 또는 다른 컨테이너로부터 격리된 시스템 자원과 네트워크를 사용하는 프로세스로 이미지는 읽기 전용으로 사용하여 변경사항은 컨테이너 계층에 저장한다.
- 컨테이너에서 무엇을 하든 이미지에 영향을 주지 않는다.
#컨테이너간 DB 연결
docker run -d --name wordpressdb -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=wordpress mysql:5.7
docker run -d --name wordpress -e WORDPRESS_DB_HOST=mysql -e WORDPRESS_DB_USER=root -e WORDPRESS_DB_PASSWORD=password --link wordpressdb:mysql -p 80 wordpress
docker run -i -t --name mysql_attach_test -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=wordpress mysql:5.7
#볼륨 지정
docker run -d --name wordpressdb_hostvolume -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=wordpress -v C:\dockerDB:/var/lib/mysql mysql:5.7
docker run -d -e WORDPRESS_DB_PASSWORD=password --name wordpress_hostvolume --link wordpressdb_hostvolume:mysql -p 80 wordpress
#네트워크 브리지
docker network create --driver bridge mybridge
docker network inspect bridge
docker run -i -t --name mynetwork_container --net mybridge ubuntu:14.04
docker network disconnect mybridge mynetwork_container
docker network connect mybridge mynetwork_container
docker run -i -t -d --name network_container_1 ubuntu:14.04
docker run -i -t -d --name network_container_2 --net container:network_container_1 ubuntu:14.04
docker exec network_container_1 ifconfig 완전히 같은 IP 주소
docker exec network_container_2 ifconfig 완전히 같은 IP 주소
docker network ls # 네트워크 종류 나열
docker run -i -t -d --name network_alias_container1 --net mybridge --net-alias alicek106 ubuntu:14.04
docker run -i -t -d --name network_alias_container2 --net mybridge --net-alias alicek106 ubuntu:14.04
docker run -i -t -d --name network_alias_container3 --net mybridge --net-alias alicek106 ubuntu:14.04
docker inspect network_alias_container1
docker inspect network_alias_container2
docker inspect network_alias_container3
docker run -i -t --name network_alias_ping --net mybridge ubuntu:14.04
#라운드로빈
docker exec -i -t {container_id _2~4} /bin/bash
ping -c 1 alicek106 # 반복 할때마다 IP주소가 다름
apt-get update
apt-get install dnsutils
dig alicek106 # 반복 할때마다 순서가 다름, 이 중 맨 위에 아이피를 반환
#컨테이너 로깅
docker run -d --name mysql -e MYSQL_ROOT_PASSWORD=1234 mysql:5.7
docker logs mysql
docker run -d --name no_passwd_mysql mysql:5.7
docker logs no_passwd_mysql
docker logs --tail 2 mysql
docker logs -f -t mysql
docker run -i -t --name logstest ubuntu:14.04
# echo test!
docker logs logstest
#로그파일 용량분할
docker run -it --log-opt max-size=10k --log-opt max-file=3 --name log-test ubuntu:14.04
syslog로그
docker run -d --name syslog_container --log-driver=syslog ubuntu:14.04 echo syslogtest # 윈도우에서는 안됨
#fluentd 로깅 - -- 도커서버 -> fluentd 서버 -> 몽고DB
docker run --name mongoDB -d -p 27017:27017 mongo # 몽고DB서버에서 가능
docker run -d --name fluentd -p 24224:24224 -v C:\dockerDBandPrt\fluent.conf:/fluentd/etc/fluent.conf -e FLUENTD_CONF=fluent.conf alicek106/fluentd:mongo #fluentd 서버에서 가능
docker run -p 80:80 -d --log-driver=fluentd --log-opt fluentd-address=192.168.0.136:24224 --log-opt tag=docker.nginx.webserver nginx
#컨테이너 메모리제한
docker run -d --memory="1g" --name memory_1g nginx
docker inspect memory_1g
docker run -d --name memory_4m --memory="6m" mysql:5.7 # 메모리가 부족하여 실행되지 않음
docker run -it --name swap_500m --memory=200m --memory-swap=500m ubuntu:14.04 # 기본적으로 swap 메모리 500MB, 메모리 200MB로 지정함
#컨테이너 CPU제한
docker run -i -t --name cpu_share --cpu-shares 1024 ubuntu:14.04
....
#도커 이미지 생성
docker run -i -t --name commit_test ubuntu:14.04
$ echo test_first! >> first
docker commit -a "alicek106" -m "my first commit" commit_test commit_test:first
docker images
docker run -i -t --name commit_test2 commit_test:first
$ echo test_second! >> second
docker commit -a "alieck106" -m "my second commit" commit_test2 commit_test:second
#도커 이미지 삭제
docker rmi commit_test:first
#컨테이너에서 사용중인 이미지를 강제로 삭제한경우 이미지 이름이 <none>로 바뀜 - 이를 댕글링 이미지라고 한다. docker images -f dangling=true 로 확인 가능
docker stop commit_test2
docker rm commit_test2
docker rmi commit_test:first
> Untagged: commit_test:first # 이미지를 사용중인 컨테이너가 존재하여 이름만 삭제
docker rmi commit_test:second # 사용중인 컨테이너가 없으므로 바로 삭제
> Deleted: sha256:2eda02a0b0564298ce3fb95799c30c682be4acb066bc980ff20bc8a45c098837
> Deleted: sha256:512a514b8ebdeac30af5cc06e35c13909b8f64a1d8aea9c2c04f6686f0bed4fd
> Deleted: sha256:9cd515720e38bf4c14c86591455f2c7265340e6ee5dbf84da2425e855830265a
> Deleted: sha256:3a2bf32d2c1d87f7bdaa7cf45847673154ca3f73b4faadc2ac98acf875bcd5cc
# 이미지 추출
docker save -o ubuntu_14_04.tar ubuntu:14.04
docker load -i .\ubuntu_14_04.tar
# 도커 허브에 이미지 올리기
docker run -i -t --name commit_container1 ubuntu:14.04
$ echo my first push >> test
docker commit commit_container1 my-image-name:0.0
docker tag my-image-name:0.0 tthinbee/my-image-name:0.0
docker push tthinbee/my-image-name:0.0
-- 내려받기 : docker pull tthinbee/my-image-name:0.0
** Dockerfile 생성
- 기본적인 도커이미지 생성 방법
1. 도커허브에 있는 이미지를 이용하여 컨테이너 생성
2. 애플리케이션 설치
3. 컨테이너 커밋
-> 새로운이미지
- Dockerfile 로 이미지를 생성하는 방법
1. Dockerfile 작성 -> 새로운이미지
└ 설치해야하는 패키지, 추가해야하는 소스코드, 실행해야하는 명령어와 셸 스크립트를 하나의 파일에 기록한 파일
# Dockerfile 빌드(build) --> 이름이 Dockerfile 인 경우
docker build -t mybuild:0.0 ./
# 빌드된 도커이미지로 컨테이너 생성
docker run -d -P --name myserver mybuild:0.0
# Dockerfile 빌드(build) --> 이름이 Dockerfile 이 아닌 경우 도커파일명 명시
docker build -f Dockerfile2 -t mycache:0.0 ./
# 캐시를사용하지 않고 처음부터 다시 빌드
docker build --no-cache -t mybuild:0.0 ./
docker build --cache-from nginx -t my_extend_nginx:0.0 ./
'DevOps와 Infra > Docker' 카테고리의 다른 글
Docker Run (0) | 2023.08.02 |
---|---|
Docker Install - EC2 (0) | 2023.08.02 |
Docker Image -> Nexus Push (0) | 2023.04.13 |
Docker 정리 (0) | 2023.02.07 |