등장 배경
전통적 프로세스 :
- 같은 OS, CPU 등의 환경이여아 프로그램이 돌아간다, 사실상 동일기계여야 돌아감
- 마이크로 소프트웨어 PC 세데에선 OS, 환경들이 동일했으므로 같은 환경이어서 동작했었다
But 웹의 등장 이후 :
- 모든 소프트웨어는 웹에서 서비스 하게 되었다.
- VM 은 같은 OS여도 보조 앱들이나 라이브러리 디펜던시가 다를 수도 있다.
- VM은 비교적 무거움
Image vs Container
- Image : 조리법(레시피), Container는 만들어진 요리, 실제 사용되는 프로세스
- Stopped Container : 만들어서 냉장고에 보관한 요리
세상의 모든 SW는 Containerized 되어 제공된다.
- Container 배포 = SW 배포
- Container 테스팅 = SW 테스팅
- Containerized된 어플리케이션 앱 = 프로세스
- 그 앱이 실행되는데 필요한 환경, OS, 커널, 비표준 라이브러리 등의 환경(Helper Process)까지 장착하여 한 패키지로 되어 어디서나 실행할 수 있도록 만들어짐
- Container Engine : 컨테이너를 동작시키기 위한 OS 수준에서 Virtualize 를 해준다.
Docker Hub
- Container 이미지들을 모아둔 Github 같은 저장소이다. 하지만 최근 대부분 Github 사용
VM vs Container
- VM : OS가 다같이 들어있으므로 과도한 메모리 점유, 느린 부팅시간, 여러 VM 실행시 성능 저하, Portability 제한, VM 사이 데이터 공유 불가능, 낮은 효율
- Container : 낮은 메모리 점유, (각 app은 미니멀하게 dependancy만 가지고 있다), 빠른 부팅 시간, 훨씬 많은 수의 container 실행 가능, platform에 좌우되지 않음, 여러 Container끼리 데이터 공유 가능, 높은 효율
Container
- App 과 App 실행에 필요한 모든 Dependency 를 묶은 Package
- 지정된 OS 위에서는 Container가 실행될 수 있도록 container engine을 기계에 장착 = 이건 OS level에서의 virtualization 을 app에 제공하는 것.
Container의 일생
- Docker Hub 에서 pull/push 로 Image를 가져옴, 이건 환경을 만드는데 필요한 템플릿(코드,시스템,OS 다 포함됨) 이다.
- 또한 Docker File 이라는 텍스트 파일에 이미지 생성 명령과 규정을 적어두고 BUILD(코드+환경까지 같이 컴파일) 해서 Image를 만들수도 있다.
- 이 Image를 RUN 시켜서 Container 를 만듬, 이건 이미지의 instance 라고 볼 수 있음
- Container는 STOP과 DELETE 하면 사라짐
Docker 설치 및 기본 명령
sudo apt-get install docker.io
docker run hello-world
- hello-world 라는 dockerhub의 기본 이미지를 가져와서 run하는것. 실제로는 pull 후 run 해야하지만 이건 맛보기
sudo usermod -aG docker $USER
- docker란 그룹에 나를(ubuntu) add 해란 뜻-> sudo 쓸 필요 없다.
cat /ect/group
- add 됐는지 확인 가능
Docker 기본 명령 (ubuntu 사용 예시)
docker pull ubuntu // ubuntu 커널 가져오기
docker images //현재 가져온 이미지 확인하기, 이미지 사이즈 확인 가능
#RUN(이미지로부터 컨테이너 만듬)
docker run -it -d ubuntu // 여기선 우분투를 RUN
= interactive 하게 우분투 커널을 detached 모드로 RUN 실행만 시키겠다, OS를 demo로 만들어서 동작시켜라
-> terminal 하게 bash shell에서 쓸수있도록, 즉 현재 ubuntu 기계에서 ubuntu OS 를 쓰도록 해준다.
docker ps
= 현재 process 들의 상태를 알려준다.
#EXEC(그 컨테이너 실행)
docker exec -it <container id> <prorm in the container>
- <ps로 확인한 컨테이너이름> bash 로 작성했었다.
-> </ps로 확인한 컨테이너이름>이후 우분투 OS root로, 즉 컨테이너 안으로 들어옴
exit
- 그 우분투 OS 에서 나가기
#STOP
docker stop <container id>
docker kill <container id>
docker ps -a //모두 확인
#REMOVE
docker rm-f <container id> //컨테이너 프로세스를 제거
docker rmi-f <image id> //이미지를 제거
Containerized Web Service 실습
docker exec -it <container id> bash 이후, 즉 EXEC 이후
1. apache2 설치
apt-get update
apt-get install -y apache2
2. vim 설치 후 /var/www 에서 html 문서 작성하기
cd /var/www
apt get install -y vim
vim 1.html // 작성함
3. 우분투 root에서 빠져나옴
exit
4. 은 laker99/firstweb 처럼 내가 웹 서비스 컨테이너를 이미지로 만든것임
docker commit <container id> <new image name>
5. 이미지 및 프로세스 확인
docker images // image size 확인가능
docker ps // 실행중인 프로세스 확인 가능
6. #WEBSERVICE CONTAINER 실행
6-1. 이 이미지를 81번 포트로 포트포워딩 함. (디폴트는 TCP80)
6-2. EC2의 security inbound rule 에서 TCP 81 열기 브라우저는 IP:81
docker run -it -p 81:80 -d laker99/firstweb
docker ps
docker exec -it <container id> bash //docker ps 에서 확인한 container id 를 적기
7. #CONTAINER 속에서
Service apache2 status //상태확인
Service apache2 start //시작
Exit
Dockerfile
= Docker image를 만들기 위해 내리는 순차적인 command들을 모아둔 text 파일
- docker command 들을 입력하여 container 를 수동으로 생성하는 대신에 Dockerfile 안의 Docker build command를 사용해서 container 생성
기존 vs Dockerfile
기존: image -> RUN -> container -> EXEC -> inside the container -> do jobs -> exit -> COMMIT -> save a new image
Dockerfile 이용 : Dockerfile -> BUILD -> Docker Image -> RUN -> Docker container
Dockerfile 기본 구문
FROM : base image 지정, 기본적으론 OS ex)ubuntu
RUN : base image 위에 추가 SW 계층 설치, image 생성 시점에 사용할 명령어 지정
ADD : ADD <source> <컨테이너내 목적지> 로 파일들을 복사함. COPY와 다른점은 source로 url 을 사용가능
CMD : container 안에서 실행하려 하는 command, container 실행 시 실행되는 명령어를 지정한다.
ENTRYPOINT : CMD 와 유사
ENV : container에서 사용할 Environment 환경 변수를 지정
예시
docker run -it ubuntu bash // docker 구문
- entrypoint는 /bin/sh -c (Docker 는 /bin/sh-c를 디폴트 entrypoint )
- image는 ubuntu
- command는 bash
Dockerfile 예시
- 반드시 vim Dockerfile 라는 이름으로 해야함
FROM ubuntu ##이 커널을 쓸테니 dockerhub에서 ubuntu 이미지를 가져와라
ENV DEBIAN_FRONTEND noninteractive
ENV DEBCONF_NONINTERACTIVE_SEEN true
## 이걸 쓰면 이미지 만들때 Timezone설정하라는 등 뭐 안나옴. interactive 모드 끄는것
RUN apt-get update ## docker image만드는데 필요한 명령어니까 RUN 작동
RUN apt-get install -y apache2
ADD . /var/www/htm
## 현재 디렉토리, 즉 커널 디렉토리의 모든 파일을 모두 다 특정 디렉토리 (html)로 카피(add)하란 명령어임
ENTRYPOINT apache2ctl -D FOREGROUND
## FOREGROUND 의미 : 이게 없으면 Entrypoint에 지정되어있는 apache2ctl을 호출하고 그냥 끝난 후 container process stop되어 아무일도 안벌어짐
## ENTRYPOINT는 반드시 한줄만 있으며 container를 run 시킨 후 해당 container에 entry 하는것 == 위에 bash해서 그 안에서 Service apache2 start 와 같다
ENV env_var_name <변수 이름>
- 이렇게 dockerfile 작성후 이 dockerfile 로 빌드하자
BUILD
docker build . -t <image name>
ex) docker build . -t laker99/test
1.
- docker file로부터 이미지 만들기 ex) laker99/test
- .는 현재 디렉토리의 (dockerfile)의미, t는 태그를 의미, image name은 만들 이미지 이름
docker run -it -p <host port #:container port#> -d <image>
ex) docker run -it -p 81:80 -d laker99/test
docker run -it -p <port #:port #> -v <local dir : mounting point dir in container> -d <image>
ex) docker run -it -p 81:80 -v ~/dockerfile:/var/www/html -d laker99/test
= 호스트기계의 디렉토리(~/dockerfile)를 컨테이너의 디렉토리(/var/www/html)에 마운트 시킨것이다.
= volume 쓰면 실행 이후 즉 kill 하지 않은 돌고 있는 상태에서 html 파일을 고칠수있다. 파일내용 업데이트 시 그대로 반영
* Docker에서 “마운트"는 컨테이너 외부에있는 데이터를 컨테이너에서 사용할 수 있는 상태가 될 것을 의미한다.
Docker-compose
- 다수의 docker container들을 규정하고 실행하고 관리하는 automation 도구 (서로 연동법등 규정)
- 여태까지 했던 것들은 단일 container를 만드는 것이었다.
- but 요즘 웹서비스는 한덩어리 프로그램이 아님. 여러개가 돌아감.
Monolithic App vs Microservices
Monolithic App : 비현실, 비효율, 낮은 생산성, 하나의 앱 vs
Microservices : 각 단일 서비스가 서로 느슨하게 결합, 그 사이에서는 HTTP 통신 프로토콜을 이용해서 데이터 교환(REST-API JSON)
* 여러개의 프로세스들 = 개별적인 container들 이 모여서 하나의 서비스
- 그래서 다수의 컨테이너를 만들어야함 -> docker compose 사용
Docker-compose 를 우분투에 깔아보자
mkdir test;
cd test;
vim docker-compose.yml
- docker compose 사용위해선 이 .yml 포멧의 텍스트파일 사용해아함. 이게 2개이상이 한 디렉토리에 있어선 안된다.
version: '3.9' //compose file version
service:
hello-world: // 컨테이너 하나
image: hello-world:latest // 가장 최신걸로 이미지인 hello-world를 가져와라
- 키는 version, ' ' 으로 value 와 key 구분
- service의 value는 또다른 key-vaule 짝
- hello-world 의 value는 또다른 key-value 짝
- image의 value는 hello-world:latest
.yml 파일 작성 후
docker-compose up -d // .yml을 실행해라, 지금은 연습이니 container 하나만 docker ps
.yml 실행하기
예시. wordpress 를 만들어보자
- 여기선 1개 host기계에서 2개 컨테이너를 실행할 것이지만 실제로는 2개 host에서 함
version: "3.9"
service:
db: //라는 컨테이너임
image: mysql:5.7
volumes: //DB 서비스가 사용하는 volume을 create 함.
- db_data:/var/lib/mysql // name volume 이다. db-data는 volume이름을 작명한 것이고 docker가 이걸 알아서 volume을 만듬
restart: always
environment:
MYSQL_ROOT_PASSWORD: somewordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress // MYSQL에 필요한 것들을 environment 변수로 작성해줌
wordpress: //wordpress 컨테이너
depends_on: -db // db란 이름의 서비스에 depend한다는 의미, 즉 위에 있는 db의 결과를 사용한다. db:가 wordpress: 보다 위에 써져있어야만 함
image: wordpress:latest // 가져와
volumes:
- wordpress_data:/var/www/html //name volume이다. wordpress_data를 여기 /var/www/html에 마운트 시키란 의미
ports: - "8000:80" //8000번으로 포트포워딩 시키기
restart: always
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_DB_NAME: wordpress
volumes: //named volumes
data_base: {}
wordpress_data: {}
이 .yml 파일 작성 후 그 디렉토리에서 docker-compose up -d 하면 됨
Docker Volume
메모리 구조
- container의 가상파일시스템(var/lib/mysql) 이 있고 그 바깥에 host machine의 host의 file system 이 있다.
Docker Volume 배경
Container에는 그 안 자체의 메모리앱이 있다., 모두 in 메모리 os리소스이다.
Container를 만든 의도는 메모리상에서만 실행되면 되는 app들을 위해 만들어진것이다.
하지만 persistant한 storage에 OS를 write/read file 서비스 하는 container를 만들어야 할때를 위해 docker volume을 만든 것.
-> 호스트 기계의 on-disk persistent filesystem을 컨테이너의 in-memory virtual filesystem에 mount 하여, 컨테이너가 종료되어도 데이터가 사라지지 않고 호스트 기계의 파일 시스템에 저장되어 다시 동일 컨테이너가 시작되어 과거 데이터를 사용할 수 있도록 제공된 기능.
- DB를 사용하는 컨테이너의 경우에는 필수적
Docker Volume의 세가지 타입
1. Host volume
docker run -v /home/mount/data:/var/lib/mysql/data
- : 의 앞에서 : 뒤로 마운트, 호스트 기계의 파일 시스템 디렉토리가 앞,
- 이게 호스트 볼륩 방식으로 마운트 시키기인데 실제론 사용안함
- 이유: 내 마음대로 원하는 호스트기계 파일 디렉토리 만드는거라 다른 사람들은 경로를 모른다.
2. Anonymous volume
docker run -v /var/lib/mysql/data
- 호스트 기계의 볼륨을 지정안했음
- docker가 호스트 기계의 정해진 경로에 폴더를 생성하는데 random hash하여 경로 이름을 달리함.
- yml 설치 이후 이 디렉토리에 호스트 볼륨 자동으로 만들어줌
- 이름 필요없을때 사용
3. named volume
docker run -v name:/var/lib/mysql/data
- docker가 생성하게 하되 생성된 볼륨에 이름을 붙여서 여러 컨테이너가 이름을 통해 공유할수있도록함.
컨테이너 간 통신
- 독립된 OS 가진 다른 컨테이너끼리는 같은 기기더라도 네트워크 통해 통신해야하는데 이때 내부 private network에서 rest-api (json)형식으로 통신한다.
+ docker swarm 또는 전통적인 분산환경에서의 동일한 종류의 서비스 제공은 서로 다른 호스트에 같은 서비스를 제공하는것, 외부로부터의 서비스 요구를 여러 호스트에 나누어 할당하는 reverse proxy 이용
*curl : 컴과 컴 사이에서 데이터를 주고받는 어플리케이션, 그 사이에서 프로토콜의 지정없이 귀찮은 작업을 다 해줌 확인가능