BOAZ 멘멘 A조 2주차
목차
설치
Docker Desktop vs. Docker Engine
•
Docker Desktop은 Docker Engine + 여러가지 툴들
Docker 사용을 위한 시스템 사양 체크
•
2023년 5월 기준
◦
맥
▪
최소 4GB의 메모리
▪
맥 OS 버전 11 혹은 그 이상
◦
윈도우
▪
최소 4GB의 메모리
▪
64비트 윈도우 10이나 윈도우 11
▪
그 이외에 다른 조건이 존재
◦
예) Hyper-V와 Container 기능이 활성화되어 있어야함
◦
예) WSL 버전 (이는 윈도우 위에서 돌아가는 리눅스 커널)
Docker 필요한 이유와 도커 개념
내 컴퓨터 환경을 그대로 패키징해서 다른 이에게 줄 수 있다면?
•
Docker Image: 이렇게 독립적으로 완전하게 만들어진 패키지
•
Docker Container: 이 Docker Image를 독립된 환경에서 실행한 것
도커의 목표는 소프트웨어를 일관되게 빌드하고 실행, 배포하는 것에 있습니다.
Virtual Machine 소개
•
AWS의 EC2가 대표적인 Virtual Machine (VM)
•
하드웨어를 추상화하여 한 컴퓨터 위에 가상 컴퓨터를 올리는 것
◦
즉 컴퓨터 하드웨어 단의 추상화
▪
Virtual Machines
보통 하나의 컴퓨터 위에 다수의 VM을 실행하는 것이 일반적
이 안에서 소프트웨어가 동작
▪
VM을 생성하고 관리하기 위한 소프트웨어: VMWare, VirtualBox, Hyper-v, …
Virtual Machine의 장단점
•
장점
◦
소프트웨어를 실행하기 위한 독립적이고 분리된 공간을 제공
◦
다수의 소프트웨어를 각 VM단에서 독립적으로 실행가능
•
단점
◦
각 VM은 자신만의 OS를 필요로 함 (가상 하드웨어 위에서 돌기 때문)
▪
유료 OS라면 라이센스 비용 필요
▪
그러다보니 시작하는데 오래 걸림
◦
자원을 많이 사용함 (VM들끼리 자원을 나눠써야함)
Docker Container 소개
•
소프트웨어를 실행하기 위한 독립적이고 분리된 공간
◦
도커(컨테이너 가상화)는 OS에서 제공하는 자원격리 기술을 이용하여 컨테이너라는 단위로 서비스를 분리할 수 있게 만들어주고, 개발환경에 대한 걱정없이 배포가 가능
•
자체 파일 시스템을 갖고 있음 (Volume이라고 부름)
Container의 장단점
•
장점
◦
소프트웨어를 실행하기 위한 독립적이고 분리된 공간을 제공
▪
다수의 소프트웨어를 각 컨테이너단에서 독립적으로 실행가능
◦
자원 소비가 적음 (lightweight)
▪
몇 십개에서 몇 백개의 container를 실행 가능
◦
호스트 OS를 사용 (별도 비용 없음)
▪
따라서 빠르게 실행됨
•
단점
◦
Host OS를 사용하기에 Cross-platform compatibility를 항상 지원하지 않음
◦
GUI 소프트웨어 개발에 적합치 않음
◦
많은 수의 Docker Container를
◦
◦
◦
◦
‘관리하는 것은 쉽지 않음
▪
컨테이너 오케스트레이션이 필요 (k8s, Docker swarm 등등)
•
Virtual Machines와 (Docker) Containers 비교
◦
가장 큰 차이점은 아래와 같다.
Guest OS가 VM에서는 풀(full OS)로 설치해야 사용 가능하고, docker에서는 격리 개념으로 분리된다는 것.
docker에서는 Host OS(Linux)와 다른 부분만 컨테이너에 있고, 커널은 Host OS와 공유하는 방식이다.
도커는 여러 컨테이너들간의 호스트 자원을 분리해서 사용하게 해준다.
이것은 리눅스 고유기술인 name space와 cgroup를 사용하여 격리하는 것이다.
시스템 구조적으로 컨테이너는 한 OS를 공유하는 구조이고 VM은 각각의 OS를 띄워야하는 구조이기 때문에 컨테이너가 빠르다.
VM은 사용자가 윈도우를 사용하고 있더라도 새로운 GuestOS를 설치할 때 리눅스 OS를 설치해서 사용할 수 있지만, 컨테이너는 리눅스 OS에서 윈도우용 컨테이너를 사용할 수 없다.
도커 프로그램 개발 프로세스
하이레벨 Docker 사용 프로세스
•
먼저 대상 소프트웨어를 선택
•
다수의 컴포넌트로 구성되는 소프트웨어라면 각각이 Docker Image로 만들어져야할 수도 있음
•
이를 Docker Image로 빌드하자: Dockerization이라고 부름
◦
Dockerfile이란 텍스트 파일로 세부 정보를 기술
▪
해당 소프트웨어를 이미지로 바꾸기 위한 Docker에게 주는 명령들을 포함
◦
Docker Image: 하나의 Docker Container안에서 실행됨!
▪
Dockerfile을 기준으로 만들어지며 소프트웨어를 실행하기위해 필요한 모든 것을 포함
•
docker build -t tag
Docker Image
Docker Image의 구성 요소
•
기본 OS (리눅스라면 우분투, 데비안 등등)와 같은 소프트웨어의 실행환경
•
소프트웨어 자체 (코드)
•
소프트웨어가 필요로 하는 라이브러리
•
파일 시스템 스냅샷: 이는 스택화된 형태로 구현됨 (뒤에서 더 설명)
•
환경 설정 변수: 빌드할 때 변수와 실행 때 변수 두 가지가 존재
◦
ENV, ARG
•
메타 데이터: 이미지 자체에 대한 정보 (버전, 작성자, 설명 등등)
위 정보와 설치 관련 실행 순서등이 Dockerfile에 기술됨
Docker Image는 다수의 파일로 구성됨 (“docker image ls”)
Docker Image의 실행
•
Container를 통해 Docker Image안의 소프트웨어를 실행
◦
Container는 자체 파일 시스템을 가진 특수한 프로세스로 이미지의 파일 시스템이 로딩됨
•
Image를 Container 안에서 실행
◦
docker run … : 이미지를 컨테이너로 띄우는 것
◦
docker exec
▪
이미 실행 중인 도커에 명령을 내림
Docker Image의 등록: Docker Hub
•
Docker Registry는 Docker Image들의 보관소
◦
On-prem registry와 Cloud registry가 존재
◦
docker hub이 가장 유명
•
여기에 등록을 하면 회사내 혹은 퍼블릭하게 이미지를 공유 가능
Docker Hub이란 무엇인가?
•
Docker가 제공해주는 서비스로 Docker Image를 공유하고 찾기 위한 서비스
•
Teams & Organizations
•
Public과 Private Repo 제공
•
Official Images
•
Github과 연동을 통한 Automated Build 제공
•
최종 환경
간단한 Hello World 프로그램 실습을 통한 Dockerfile 작성
전체적인 프로세스
•
cd node
◦
OS 선택
◦
Node 설치
◦
코드 복사
◦
프로그램 실행 (node app.js)
Dockerfile의 생성
•
•
Docker에게 소프트웨어 설치 명령을 기술
◦
먼저 베이스 이미지를 기술 (FROM)
◦
다음으로 코드 복사
◦
마지막으로 코드 실행
•
FROM : OS 종류를 적어줌.
여기서는 Alpine이라는 경량 리눅스를 데모 목적으로 선택
•
COPY : 코드 복사
•
WORKDIR : working directory
•
CMD : 실행하는 명령 앞에 지정
•
ARG:
◦
도커 이미지 빌드를 위해 Dockerfile 내에서 사용하는 변수
▪
빌드 시점에 사용하며, docker build 명령의 --build-arg 옵션에 해당한다.
◦
Docker Image를 만들 때 사용되는 변수 지정. 최종 이미지에는 안 들어감
•
ENV
◦
환경변수를 설정하는 명령어
▪
설정된 환경 변수는 이미지 빌드 시 사용되며, 해당 이미지를 실행한 컨테이너 내에서 사용할 수 있다.
▪
docker run 명령의 -e 옵션에 해당한다.
▪
$JAVA_HOME
◦
컨테이너가 실행될 때 사용되는 환경변수. 최종 이미지에 저장됨
•
USER
◦
컨테이너를 실행할 때 사용할 유저 ID
•
EXPOSE
◦
서비스 사용 포트번호
•
RUN
◦
빌드시 실행되어야하는 명령들이 지정됨 (docker build)
◦
RUN apt-get update && apt-get install -y curl
Dockerfile 키워드: CMD vs. ENTRYPOINT
•
둘 다 컨테이너 시작시 실행할 명령어를 지정해준다. 컨테이너를 시작하려면 둘 중에 하나는 지정해주어야 한다.
•
CMD
◦
컨테이너를 생성할 때만 실행됩니다. (docker run)
◦
컨테이너 생성 시, 추가적인 명령어에 따라 설정한 명령어를 수정할 수 있습니다.
•
ENTRYPOINT
◦
컨테이너를 시작할 때마다 실행됩니다. (docker start)
◦
컨테이너 시작 시, 추가적인 명령어 존재 여부와 상관 없이 무조건 실행됩니다.
•
Container가 시작할 때 실행되어야 하는 명령어를 지정하는데 사용 (docker run)
◦
굉장히 흡사한 기능을 제공하지만 동시 사용시, ENTRYPOINT에 우선 순위가 있음
•
둘 다 한 DOCKERFILE에서 여러 번 실행되면 각각 마지막 명령 줄만 사용됨
◦
아래의 경우 docker run 실행시 동일한 결과가 나옴
•
ENTRYPOINT 명령어는 오버라이딩이 어렵고 CMD 명령어는 오버라이딩이 쉽다.
◦
ENTRYPOINT는 --entrypoint 옵션을 통해서만 덮어쓰기가 가능
•
CMD나 ENTRYPOINT 중 하나만 지정되면 그게 container가 실행될 때 실행
◦
CMD cli 오버라이딩
◦
둘이 한 DOCKERFILE에서 같이 지정 가능함
◦
둘이 같이 사용되면 ENTRYPOINT가 기본 명령이 되고 CMD가 인자를 제공
•
결국 CMD or ENTRYPOINT?
◦
️ Best Practice는 CMD 사용
◦
최대한 CMD만 사용
▪
항상 실행해야 하는 명령을 사용하여 실행 가능한 도커 이미지를 빌드할 때는 ENTRYPOINT를 사용한다.
▪
CMD 명령어는 도커 컨테이너가 실행될 때 command line에 명시적으로 인자값을 지정하지 않는 경우에 기본 명령어 역할을 하는 인자를 설정하는 데에 사용한다.
▪
ENTRYPOINT를 사용하면 실행시 타이핑을 덜 할 수 있음
▪
파라미터를 지정해주면 되기 때문이지만 감춰지기 때문에 오히려 혼란을 줄 수 있음
▪
요약:
1.
ENTRYPOINT가 있으면 CMD 값이 파라미터로 실행됨
2.
아니면 CMD가 실행됨
남이 만든 Dockerfile : Airflow 리뷰
풀 도커파일
•
ARG는 빌드 타임에도 사용이 되지만, 이미지에도 최종 저장이 된다. 컨테이너가 실행될 때도 이용 가능한 변수가 된다
◦
CMD에서도 이용 가능함
•
USER : 컨테이너를 돌리는 유저 이름
•
Entry point를 통해 명령 실행 후, CMD로 파라미터 입력
Docker Image 생성 및 컨테이너 빌드
•
docker build --platform linux/amd64 -t hello-world-docker .
•
docker build -t hello-world-docker .
docker build --platform linux/amd64 -t hello-world-docker .
Bash
복사
=> [internal] load build definition from Dockerfile
…
=> => writing image
sha256:cb6c638168780afd3d74fc1cddd813917a6a397dad453c8e1a8063635c1521fe 0.0s
=> => naming to docker.io/library/hello-world-docker
Plain Text
복사
docker build를 실행하면 Dockerfile에서 RUN 명령이 실행됨
1.
만일 Apple M1 chip 기반 맥에서 빌드하는 경우 그 이미지는 ARM 기반 아키텍처로 만들어지기 때문에 일반 리눅스에서 안 돌아감. 그래서 --platform 옵션을 사용해서 linux/amd64로 지정
2.
t는 태그를 지정하는 것으로 뒤에서 더 설명
•
Docker Image 확인
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world-docker latest cb6c63816878 22 minutes ago 179MB
SQL
복사
•
Docker Container로 실행
$ docker run hello-world-docker
>> docker run을 Dockerfile에서 CMD 명령이 실행됨
Hello Docker!
SQL
복사
•
만일 이 이미지를 다른 컴퓨터에서 실행하고자 한다면?
◦
Docker Registry (예를 들면 Docker hub)으로 먼저 등록
Docker HUB 등록
Docker Registry에 등록
1.
Docker Hub 회원등록
•
먼저 Docker Hub에 회원 등록: https://hub.docker.com/
◦
ID와 Password를 기억해둘 것
2.
hello-world-docker repo 만들기
•
Create repository 선택
•
이름을 “hello-world-docker”로 지정. Public 속성 지정:
◦
hajun/hello-world-docker
3.
Docker Registry에 등록
•
터미널로 이동하여 다음 명령을 실행
•
먼저 현재 이미지의 repo 이름을 hajun/hello-world-docker로 변경
$ docker image ls
$ docker tag hello-world-docker:latest hajun/hello-world-docker:latest
$ docker image ls
$ docker login --username=hajun
>> 별도의 프롬프트로 물어봅니다.
$ docker push hajun/hello-world-docker
SQL
복사
4.
Docker Hub에서 결과 확인
Docker 명령 요약
•
docker version
•
docker build -t
•
docker push
•
docker login
•
docker tag
•
docker pull
•
docker run
◦
-p option (port mapping)
◦
-v option (volume mapping)
docker run vs. docker exec
•
docker run과 docker exec의 차이점은 무엇일까?
◦
docker run은 새로 Container를 실행하는 것
◦
docker exec는 실행된 Container에 작업을 하는 것
▪
그래서 이 명령은 Container ID가 필요함
▪
인터렉티브하게 명령을 내릴 때 옵션
•
-it 옵션
•
docker exec -it container_id /bin/bash
•
두 명령 모두 --user root 혹은 -u root를 통해 루트 유저로 연결가능
•
m1의 경우, 그냥 run을 통해 빌드하게 되면, 애플 칩 위에서만 돌아가는 컨테이너가 되어버림
◦
docker build —platform linux/amd64 -t hello-world-docker .
◦
docker run hello-world-docker
Docker Image 이름?
•
docker image ls와 docker images와 동일한 결과를 보여줌
•
앞서 docker tag 명령의 경우 별칭을 만들어주는 것임 (이름을 바꾸는 것이 아님)
◦
docker tag hello-world-docker hajun/hello-world-docker
•
Docker image의 실제 ID는 IMAGE ID임
•
Image 이름 자체는 REPOSITORY 이름과 TAG로 구성됨
◦
한번에 쓰는 경우 :을 사이에 두고 같이 씀 ⇒ redis:13, hajun/hello-world-docker:latest
Docker tag란?
•
Docker Image의 버전이나 변형을 나타내는 문자열
◦
디폴트 값은 latest
◦
Docker Image의 부가정보를 나타냄
•
Docker Image 이름에서 :뒤에 해당
◦
예: ubuntu:18.04
◦
예: bitnami/airflow
◦
예: node:alpine
docker inspect
•
이미지 조사하기
◦
다음과 같이 httpd:alpine 이미지와 직접 Dockerfile로 작성한 이미지 조사해보기
⇒ docker inspect 이미지 이름
Dockerfile 내 Labels 명령어로 입력한 부분이 Label 정보로 이미지 안에도 들어가 있음
Hangman 웹서비스를 Github을 통해 Docker Image로 Docker Hub에 업로드
레포 및 코드 설명
•
Hangman 프로그램
◦
▪
git clone https://github.com/HaJunYoo/boaz-docker
▪
cd hangman_web
◦
hangman 프로그램을 flask를 사용하여 웹으로 노출
◦
포트번호는 어디든 바인딩 가능하며 실행할 때 지정
◦
flask 관련 모듈 설치가 필요함: requirements.txt
•
실행 방법
◦
python3 -m flask run --host=0.0.0.0 --port=4000
▪
이 경우 app.py를 기본으로 사용함
•
레포 구성
•
requirements txt
Flask==2.3.2
Flask-HTTPAuth==4.5.0
Flask-Login==0.6.2
Flask-SQLAlchemy==3.0.3
SQL
복사
•
app.py
from flask import Flask,session
app = Flask(__name__)
…
app.secret_key = "Python Study"
if __name__ == "__main__":
app.run()
Python
복사
•
프로그램 실행 데모
코드 설명을 간단히 한 후에 터미널에서 실행하는 데모 수행
git clone https://github.com/HaJunYoo/boaz-docker
cd hangman_web
pip3 install -r requirements.txt
python3 -m flask run --host=0.0.0.0 --port=4000
Python
복사
Hangman 서비스를 Docker Image로 구성 후 허브에 푸시
Docker 컨테이너 내부 프로세스와 호스트 프로세스간의 통신
•
Dockerfile 작성
FROM python:3.8-slim-buster
LABEL Maintainer="hajuny129@gmail.com"
# 메타데이터로 docker inspect 명령으로 찾아볼 수 있음
COPY . /app
WORKDIR /app
RUN pip3 install -r requirements.txt
EXPOSE 4000
# 이 포트 번호를 사용하니 포트 맵핑을 할때 참고하라는 정보
# 나중에 포트의 인바운드 규칙으로써 활용 가능
CMD ["python3", "-m", "flask", "run", "--host=0.0.0.0", "--port=4000"]
Python
복사
•
Docker 컨테이너로 포트 4000에 실행된 Flask app이 있다
•
그냥 docker run 하게 되면 에러가 발생
•
이 app을 호스트 운영체제에서 접근하려면?
•
Docker 컨테이너를 실행할 때 포트 맵핑을 통해 호스트 운영체제 단에서 접근되는 포트를 컨테이너쪽으로 포워드해주어야함 ⇒ -p 옵션
Docker 컨테이너 내부 프로세스가 오픈한 포트번호를 외부로 노출해주는 것이 포트 맵핑
•
이미지 빌드
docker build --platform=linux/amd64 -t hangman .
Python
복사
•
docker run 수행시 -p 옵션 사용
•
docker run -p 4000:4000 이미지이름
docker run -p 4000:4000 hangman
Python
복사
•
전체 명령어 요약
$ docker build --platform=linux/amd64 -t hangman .
$ docker image ls
$ docker inspect hajuny129/hangman
$ docker run -p 4000:4000 hajuny129/hangman
$ docker run -p 4000:4000 -d hajuny129/hangman # background run
$ docker login
$ docker push hajuny129/hangman # docker image hub에 푸시
Python
복사
•
컨테이너 ~ 이미지 삭제 방법
docker stop 컨테이너_id
docker rm 컨테이너_id
docker rmi 이미지_id
Python
복사
•
Docker image hub에 push 되었는지 확인
•
추가 명령어
○ docker inspect 명령
○ docker run "-d" 옵션
○ docker stop 명령
Python
복사
MySQL Dockerfile 실습 - (시간적 여유 될 때)
리눅스 커널과 배포판 컨테이너 사용
•
리눅스 커널: 리눅스의 핵심부분. Linus B. Torvalds가 1992년에 처음 공개
◦
배포판 : 동일한 커널을 보유, 하지만 커널 이외의 것들이 달라짐(쉘, 응용 프로그램)
어떤 리눅스 배포판이 있는가?
•
우분투: 가장 많이 사용되며 데비안에 기반해서 만들어진 리눅스 배포판
•
데비안
•
알파인: 임베드 시스템에서 사용할 용도로 만들어진 경량화 리눅스 배포판
•
페도라
•
센트OS
•
…
배포판에 따라 다른 패키지 매니저가 존재
•
npm
•
yarn
•
pip
•
apt
•
NuGet
보통은 docker image를 pull하고 run을 해야함! 바로 run을 하면?
•
docker run ubuntu
•
docker ps
•
docker ps -a
•
docker run -it ubuntu
◦
nano
▪
설치가 안되어서 없을 것
◦
apt list
◦
apt install nano
◦
apt update
◦
apt install nano
◦
nano
◦
apt remove nano
MySQL 8.0을 Docker로 실행해보기
1.
먼저 Docker Engine이 실행된 것 확인하고 terminal 프로그램 실행
2.
MySQL docker image를 다운로드
a.
docker pull mysql/mysql-server:8.0
3.
다운로드받은 이미지로 Docker container 실행
a.
docker run --name=mysql_container mysql/mysql-server:8.0
4.
MySQL root 계정의 패스워드 찾기
a.
docker logs mysql_container 2>&1 | grep GENERATED
5.
마지막으로 MySQL shell 실행하기
a.
docker exec -it mysql_container mysql -uroot -p
•
실행 예제
$ docker pull mysql/mysql-server:8.0
8.0: Pulling from mysql/mysql-server
...
38b3da6a86f7: Pull complete
Digest: sha256:5241f7de0483a70f5856da995fea98904cfce8f1c51734b7f3836c1663eead17
Status: Downloaded newer image for mysql/mysql-server:8.0
docker.io/mysql/mysql-server:8.0
$ docker run --name=mysql_container mysql/mysql-server:8.0
6137dc6ea2fe283dd007b2e55a1cc2c37b0c89dc45eaa3b58085bae7daa799ed
$ docker logs mysql_container 2>&1 | grep GENERATED
[Entrypoint] GENERATED ROOT PASSWORD: kmK,K#;bEte?65?kq41/;o4.Nd5YyV41
SQL
복사
•
컨테이너 접속
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6137dc6ea2fe mysql/mysql-server:8.0 "/entrypoint.sh my…" 8 secs ago Up 7 secs (health: starting) 3306/tcp,33060-33061/tcp mysql_container
$ docker logs mysql_container 2>&1 | grep GENERATED
[Entrypoint] GENERATED ROOT PASSWORD: [PASSWORD]
$ docker exec -it mysql_container mysql -uroot -p
Enter password:
mysql> show databases;
ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement.
mysql> ALTER USER root@localhost IDENTIFIED BY 'MeadowoodDr9$';
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.01 sec)
mysql> use mysql;
Database changed
mysql> show tables;
+------------------------------------------------------+
| Tables_in_mysql |
+------------------------------------------------------+
| columns_priv |
| component |
| db |
SQL
복사
•
기억할 명령어
◦
docker run --name
▪
기억하기 쉬운 이름을 docker ps로 찾은 Container ID 대신 사용 가능
◦
docker logs
▪
Container쪽에서 생성된 stdout, stderr단의 로그를 읽어옴
▪
--follow 옵션을 사용하면 로그가 계속적으로 스트리밍이 됨
▪
docker logs container_id —follow