[교육] PAAS

day 1 _ docker and docker compose

컨테이너

느슨하게 격리된 애플리케이션을 패키징하고 실행

  • 애플리케이션 실행에 필요한 모든 것을 패키징
    • OS에 종속적이지 않음

docker build 시작

  • docker pull : 필요 이미지를 땡김
  • docker build : 이미지를 실제 빌드
  • docker run : 이미지를 실행

도커 데몬

docker api 서버 및 런타임

도커 클라이언트

docker cli.

도커 데스크탑

그냥 데스크탑 애플리케이션. 다 들어있다(dockerd, client, kubernetes, credential helper)

도커 레지스트리

이미지 레지스트리

도커 객체

이미지, 네트워크, 볼륨 등 도커 실행에 필요한 다양한 구성 요소들

이미지

컨테이너 생성 지침이 포함된 읽기 전용 템플릿.

컨테이너

실행한 이미지. OS로 보면 프로세스. 완전히 격리되어 있으므로 기본적으로 컨테이너간 통신이 불가능함.

rocky linux

vagrant에 rocky linux 설치 centos 8은 m1 arm을 지원하지 않는다.

vagrant add box generic/rocky9
vagrant init generic/rocky9
vagrant up

repository 변경

sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-Linux-*
sed -i 's/#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org/g' /etc/yum.repos.d/CentOS-Linux-*
dnf remove podman container containers-common
dnf install y dokcer-ce-3:20.10.12-3.el8 docker-ce-cli-1:20.10.12-3.el8 containerd.io-1.4.12-3.1.el8

유저 추가

도커 컨트롤을 위한 유저 추가

groupadd docker
useradd paas -m
passwd paas
usermod -aG docker pass
docker run hello-world

도커 서비스를 활성화하여 리셋 시에도 정상 동작하는지 확인

systemctl enable docker.service
systemctl enable containerd.service

기본 구성 파일

dns를 바꾸려면 아래 경로를 참조하자.

/etc/docker/daemon.json

{
"dns" : ["8.8.8.8","8.8.4.4"]
}

docker exec -it

//https://hwan-shell.tistory.com/366 : -i나 -t만 사용했을 경우?
-i : input. 표준입출력 STDIN를 열겠다는 의미
-t : terminal. 가상 tty(pesudo tty)를 통해 접속하겠다는 의미
docker run -it ubuntu /bin/bash
docker pull <imagepath>
docker container create <imagepath>

설치 후 실행 테스트

실행 후 가볍게 웹을 하나 띄워보자.

docker run -d -p 80:80 docker/getting-started

-d 데몬 실행 -p 호스트포트:컨테이너내부포트

테스트 조작

  1. git clone https://github.com/docker/getting-started.git

  2. dockerfile 생성

FROM node:12-alpine
RUN apk add --no-cache python2 g++ make
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
EXPOSE 3000
  1. docker build -t getting-started . -t : targetname

  2. docker images

  3. docker run getting-started -d -p 3000:3000

6.확인

  1. 내용 수정

  2. 다시 빌드. docker build

  3. docker stop containe id

  4. docker run 다시

레지스트리 사용

docker tag imagename tagname docker images를 해보면 태그네임이 붙은 이미지가 하나 더 생긴것을 확인할 수 있다.

docker login 하여 레지스트리를 사용할 수 있게하고, docker push imagename with tagname를 입력하여 도커 허브 이미지 레지스트리에 등록하자.

hub.docker.com에 들어가서 로그인해보면 실제 도커 이미지가 등록된 것을 확인할 수 있다.

Docker Labs

https://labs.play-with-docker.com

컨테이너 볼륨

컨테이너는 종료시 작성/수정했던 파일들이 다 사라진다. 영속적인 데이터를 다루기 위하여 볼륨이라는 구조를 만든다. 볼륨을 생성하고 컨테이너에 붙이는 과정은 다음과 같다.

  1. 볼륨 생성
docker volume create todo-op
docker volume create todo-db
  1. 확인
docker volume list
  1. 컨테이너 시작시 생성한 볼륨을 붙여넣기
docker run -dp 3000:3000 -v volumename:path in container imagename
docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started

호스트의 소스 폴더를 워킹 디렉토리로 직접 마운팅하면, 호스트의 소스 수정이 바로 반영된다.

docker run -dp 3000:3000 -w /app -v "$(pwd):/app" node:12-alpine sh -c 'yarn install && yarn run dev'

-w /app : -w=working directory. 작업 디렉토리/현재 디렉토리를 변경한다.

멀티 컨테이너 구성

docker run -d --network todo-app --network-alias mysql -v todo-mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=secret -e MYSQL_DATABASE=todos mysql:5.7 => 볼륨 옵션이 없으면 볼륨명을 자동으로 설정하여 실행한다.

docker inspect volume volumename

마이에스큐엘과 노드제이에스 두 컨테이너를 실행하고 네트워크로 연결해서 서비스를 실행하려면 어떻게하면될까?

네트워크

네트워크 디버깅할 때 요길 쓴다. 생성한 네트워크 todo-app에 연결하여 요래조래 해보자. docker run -it --network todo-app nicolaka/netshoot

데이터베이스

데이터베이스를 실행할 때 네트워크 설정을 해준다. nodejs에서 mysql로 접근할 때 엔드포인트 정보가 있어야 하는데, 이 정보를 network-alias라는 옵션으로 추가한다. --network-alias mysql을 추가하였으므로, nodejs container내부에서 nslookup으로 mysql을 해보면 mysql을 향하나? 어쨋든 뭔가 나온다 ㅋㅋㅋ???. 이를 통하여 컨테이너에 접근할 수 있다.

-e : 환경 변수를 설정한다.

docker run -d --network todo-app --network-alias mysql -v todo-mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=secret -e MYSQL_DATABASE=todos mysql:5.7

실제 nodejs 컨테이너 실행

  • 네트워크를 만들었고(--network todo-app),
  • mysql에 접근할 엔드포인트를 설정했고(--network-alias mysql)으니
  • db접근에 필요한 정보(아이디, 비밃런호, 디비명)를 환경 변수로 던져서 실행한다.
docker run -dp 3000:3000 -w /app -v "$(pwd):/app" --network todo-app -e MYSQL_HOST=mysql -e MYSQL_USER=root -e MYSQL_PASSWORD=secret -e MYSQL_DB=todos node:12-alpine sh -c 'yarn install && yarn run dev'

이제 투두앱에 데이터를 쌓으면 mysql에 데이터가 잘 쌓이는 것을 볼 수 있다.

docker compose

docker 하나로만 돌리면 후달리니까.. 요래조래 잘 묶기 위해서 탄생한 시스템.

version: "3.7"
services:
app:
image: node:12-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 3000:3000
working_dir: /app
volumes:
- ./:/app
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASSWORD: secret
MYSQL_DB: todos
mysql:
image: mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: todos
volumes:
- todo-mysql-data:/var/lib/mysql
volumes:
todo-mysql-data:

네트워크를 별도 설정해주지 않았는데, 설정해주지 않아도 기본적으로 두 컨테이너간 통신을 위한 브릿지 네트워크가 생성이 된다. 서비스 이름이 network-alias의 endpoint이름이 된다. 이렇게 브릿지 네트워크가 생성됨.

NETWORK ID NAME DRIVER SCOPE
25a5d7dd43b6 app_default bridge local

그런데 docker-compose down이후 확인하면 해당 브릿지 네트워크가 사라져 있는 것을 알 수 있다.

docker-compose logs container service name을 통해 개별 컨테이너에 대한 로그도 볼 수 있다.

레이어캐싱 : 빌드 타임 최적화

현재 빌드의 경우 소스가 변경될때마다 yarn install을 땡겨오는 것을 알 수 있다. 그렇게해야할까? 소스만 고치면 yarn install까지 캐싱하고 그 다음 단계만 빌드할 수 있다.

비포 : 소스만 건드리더라도 copy . .에서 변화가 발생하므로 매번 yarn install을 진행한다.

FROM node:12-alpine
RUN apk add --no-cache python2 g++ make
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
EXPOSE 3000

애프터 : package.json 구성을 바꾸지 않고 소스만 바꾸면 copy . . 라인까지는 수행할 필요가 없으므로 이미지 레이어를 캐싱하고 cmd 라인부터 진행하게 된다. 매번 패키지를 안 땡겨와도 되니 개꿀이다.

FROM node:12-alpine
RUN apk add --no-cache python2 g++ make
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --production
COPY . .
CMD ["node", "src/index.js"]
EXPOSE 3000

.dockefileignore 에 ignore할 부분을 넣어두면 더 빠른 빌드가 이루어진다.

2일차 과제

  1. httpd:bullseye 이미지 가져옥이
  2. source base directory copy build
  • 대상 directory : /root/Work/httpd-test/htdocs
  • 매칭 directory : 컨테이너 내부의 htdocs directory => 절대 경로 복사가 안되므로 dockerfile을 대상 디렉토리 내부에서 생성하여야 한다. => bind할 경우는 상관 없음.
  1. 인덱스 파일 수정
  • writer: 작성자명 date : javascript를 활요한 현재시간 가져오기
  1. 신규 이미지로 빌드 후 컨테이너 수행

  2. 결과 확인

FROM httpd:bullseye
COPY . /usr/local/apache2/htdocs/
EXPOSE 80
hello, centumcity<br />
writer:jeognhan kim
<div>
date : <div id="todayDate"></div>
</div>
<script>
const date = new Date();
console.log(date);
document.getElementById("todayDate").innerHTML = date;
</script>
  1. -v옵션을 줘서 컨테이너 내부의 htdocs경로를 덮어 쓸 수 있다. 예를 들어 1) COPY . /usr/local/apache2/htdocs/명령으로 현재 폴더를 카피한 후 2) -v /var/www/public/:/usr/local/apache2/htdocs/을 실행 옵션으로 주면 호스트의 /var/www/public/경로가 컨테이너 아파치의 스태틱 페이지로 보인다. 단, 이미지 빌드는 현재 경로 기준으로 되어 있으므로, -v옵션을 빼면 현재 경로 기준의 이미지가 뜬다.