본문 바로가기

KOSA 클라우드 솔루션즈 아키텍트 양성과정

[7.13] Docker( Volume, drain, swarm)

- Volume

 

# docker volume create my-vol01
# docker volume list
# docker volume inspect my-vol01
"Mountpoint": "/var/lib/docker/volumes/my-vol01/_data"
# docker container run -itd --name vol-test -v my-vol01:/mnt centos:7
# docker container run -itd -p 801:80 --name vol-web -v my-vol01:/usr/local/apache2/htdocs:ro httpd:latest
# curl 192.168.0.151:801
<html><body><h1>It works!</h1></body></html>
# docker container exec vol-test sh -c "echo "Nihao" > /mnt/index.html"
# curl 192.168.0.151:801
Nihao

--- 도커 네트워크 관리

# docker network list
# docker network inspect bridge
"com.docker.network.bridge.name": "docker0",
# docker network create new-net --subnet 10.13.0.0/16 --ip-range 10.13.0.0/20 --gateway 10.13.0.1
# docker network list

--- onbuild 명령어 활용

 

--- 운영자 역할
# mkdir onbuild && cd $_
# vi Dockerfile.base
FROM ubuntu:18.04
RUN sed -i 's/archive.ubuntu.com/ftp.daumkakao.com/g' /etc/apt/sources.list
RUN apt-get -y update
RUN apt-get -y install nginx
EXPOSE 80
ONBUILD ADD website*.tar /var/www/html/
=> 나중에 개발자한테 받을 파일 이름이 website로 시작해야 함
CMD ["nginx", "-g", "daemon off;"]

# docker build -t skk2022/web-base:v2.0 -f Dockerfile.base .
=> -t : 태그를 의미, 일반적으로 v2.0과 같이 버전을 나타내는 부분을 태그라고 함
=> -f : file을 의미, (.)은 file의 위치가 현재 폴더라는 의미
=> 이렇게 빌드 된 이미지는 우분투에 더해 nginx까지 포함하므로, ubuntu이미지 보다 용량 커짐
# docker login
# docker push skk2022/web-base:v2.0
# vi Dockerfile
FROM skk2022/web-base:v2.0
=> web-base이미지를 베이스 이미지로 해서 전해주기 위해 만듦

--- 개발자 역할
# mkdir onbuild && cd $_
# ls
website.tar
Dockerfile

# docker build -t skk2022/web-site:v2.0 .
=> onbuild가 떨어져 나가면서 ADD명령어가 실행됨
# docker run -d -p 80:80 --name=web-site skk2022/web-site:v2.0
# docker login
# docker push skk2022/web-site:v2.0

 

 


 

--- 도커 컴포즈

 

# curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# chmod +x /usr/local/bin/docker-compose
# mkdir my_wordpress && cd $_
# vi docker-compose.yml
version: "3.3"    
services:
  dbserver:
    image: mysql:5.7
    volumes:
      - db_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wpuser
      MYSQL_PASSWORD: wppass
  wordpress:
    depends_on:
      - dbserver
    image: wordpress:latest
    volumes:
      - wordpress_data:/var/www/html
    ports:
      - "8888:80"
    restart: always
    environment:
      WORDPRESS_DB_HOST: dbserver:3306
=> 포트 번호를 넣지 않아도 되지만 넣어줌
      WORDPRESS_DB_USER: wpuser
      WORDPRESS_DB_PASSWORD: wppass
      WORDPRESS_DB_NAME: wordpress
volumes:
  db_data: {}
=> 사용하겠다는 선언
  wordpress_data: {}
=> 사용하겠다는 선언

# docker-compose up -d
# docker-compose ps
# docker-compose pause
# docker-compose unpause
# docker-compose port wordpress 80
=> wordpress의 호스트 포트로 몇 번 포트를 했는지 알고 싶을 때 사용
# docker-compose config
=> yaml 파일의 설정 내용을 다시 보여주는 것
# docker-compose stop wordpress
# docker-compose rm wordpress
# docker-compose down
=> down : stop + rm
# docker-compose down --rmi all

=> yaml 파일로 관리하는 것을 일종의 오케스트레이션이라고 보면 됨

--- 도커 컨테이너 모니터링

VERSION=v0.44.0 # use the latest release version from https://github.com/google/cadvisor/releases
docker run \
  --volume=/:/rootfs:ro \
  --volume=/var/run:/var/run:ro \
  --volume=/sys:/sys:ro \
  --volume=/var/lib/docker/:/var/lib/docker:ro \
  --volume=/dev/disk/:/dev/disk:ro \
  --publish=8080:8080 \
  --detach=true \
  --name=cadvisor \
  --privileged \
  --device=/dev/kmsg \
  gcr.io/cadvisor/cadvisor:$VERSION 
=> 도커 이미지를 담을 수 있는 구글의 레지스트리

--- 도커 스웜(cluster)

# firewall-cmd --permanent --zone=public --add-port=2377/tcp
# firewall-cmd --reload
# hostnamectl set-hostname master1

# cat <<EOF >> /etc/hosts
192.168.0.186 manager1
192.168.1.126 worker1
192.168.1.127 worker2
EOF
=> IP와 호스트 네임이 맵핑되어 도메인 네임처럼 해당 이름을 통해 ping 통신 가능

# docker swarm init --advertise-addr 192.168.0.186
init 후 토큰 정보가 생성됨

# docker swarm join --token SWMTKN-1-323ibtr5pxon87wzw7rbffd6ztqhky7r06bcpam2by7hlwd8j8-6tuh78gy3u9g042exjaq7eqym 192.168.0.186:2377
=> 여기 IP는 init을 하면 나오는 join이라는 정보를 활용
worker1과 2에 토큰 정보를 삽입

# docker node ls
manager1에서 토큰으로 연결한 worker1과 2확인 가능

# docker service create --name my_web --replicas 3 --publish published=8080,target=80 nginx
=> 배포를 위한 명령어 
=> --replicas3 : Desired state가 세 개라는 의미(controller인 manager1과 worker1, 2 포함)
=> 끝에 nginx가 이미지의 이름
=> --publish published=8080,target=80의 의미 : published는 도커 호스트, target은 컨테이너 호스트, -p 8080:80
=> 이러한 다수의 컨테이너 그룹의 이름을 my_web으로 명명
# docker service ls
# docker service ps my_web
# docker service logs my_web
# docker service inspect --pretty my_web
# docker service scale my_web=5
=> 기존에 3개 였다면 2개 더하겠다는 의미

# docker service ps my_web
# docker service rm my_web

각각의 worker는 컨테이너의 집합

- docker swarm의 최소 단위는 task

- 추후 쿠버네티스에서 task역할은 pod

- task가 컨테이너를 담고 있음

- 자아치유 기능 : Desired state가 3개 이므로, 노드가 두 개가 되면 자동으로 복제해서 한 개 더 만듦

 => 단일 장애 지점(Single Point of Failure)을 회피


--- 롤링 업데이트

 => ex) 겨울철 홈페이지에서 봄철 홈페이지로 변경할 때, 전부 지우고 다시 만들면 다운타임이 발생

  => 따라서, 실행 중에 롤링 업데이트를 통해 일부만 수정

# docker service ps my_web
# docker service inspect --pretty my_web
# docker service update --image skk2022/web-site:v1.0 my_web
=> my_web 내에 3개의 테스크 내의 컨테이너의 이미지를 바꾸는 작업
# docker service ps my_web

 --- rollback (버전 관리의 일환)

=> 업데이트를 했는데, 모종의 오류가 발생해서 이전의 홈페이지로 돌림

=> nginx 이미지의 원본으로 rollback 했기 때문에, index파일에 수정했던 내용은 롤백 되지 않음


--- 클러스터에서 특정 노드 드레인하기

# docker node ls
# docker service ps my_web
# docker node update --availability drain worker1
=> worker1에 문제가 발생해서 worker1이 가지고 있는 컨테이너를 다른 테스크에게 전해줘야 함
manager1이 코어와 메모리 더 많아서 manager1이 worker1의 컨테이너 받게 됨, 기존의 manager1과는 다름

# docker node inspect --pretty worker1
# docker service ps my_web
# docker node update --availability active worker1
=> drain 이후 worker1에서 발생한 문제를 해결한 후 다시 worker1을 active해줌
# docker node inspect --pretty worker1
# docker node ls

=> drain 후 다시 worker1을 active했을 때 docker service ps my_web 하면 worker1이 다시 실행되는 것으로 표시되지 않음

=> worker1을 다시 프로세싱 상태로 만들기 위해서 docker service scale my_web=2로 테스크 하나 줄였다가,

docker service scale my_web=3해서 원상태로 해주기

 


-- pause

pause : 현재 컨테이너는 그대로 운용하지만, scale 시 worker2에는 더 이상 배포되지 않음

 

노드는 5개로 증가하였지만, pause된 노드인 worker2는 증가하지 않음


# kubernetes

 

--개념

- 컨테이너화된 워크로드와 서비스를 관리
- 이식성, 확장 가능한 오픈소스 플랫폼
- 선언적 구성(Desired State)과 자동화를 용이하게 함
=> Desired State : ex) replicas=3으로 유지
- 프로덕션 워크로드를 대규모로 운영하는 15년 이상되는 구글의 경험과 커뮤니티의 아이디어가 결합
- 개발, 테스트, 스테이징(스테이징 환경은 있을 수도 있고 없을 수도 있음, 최종 운영 환경과 닮음) 
- 프로덕션 환경 : 최종 운영 환경을 의미(엔드 유저를 만나게 되는 환경)

 

-- kubernetes의 아키텍처

- API 혹은 API서버 : 사용자가 API 서버에 yaml 파일 형태로 API 서버에 전달
- Control plane (= master node)
- Date plane (= node, worker node)
- 엣시디(etcd) : NoSQL DB서버 => key와 value로 데이터를 저장
=> 사용자의 명령을 일단 엣시디에 저장 후 필요할 때 API서버가 해당 내용을 서치하고 쿼리하는 작업 진행
- node들이 주기적으로 API서버에 접속해서 사용자의 오더가 무엇인지 알아보러 감
=> Control plane의 kube-scheduler가 API서버로부터 노드들의 상태에 대한 정보(cpu, 메모리 등)를 보관 중
 => API서버에게 pod를 어떤 노드에 placement할 지 알려줌
- kubelet : pod를 생성하고 그 안의 컨테이너를 꾸미는 역할을 함
=> 여기서 컨테이너가 Docker를 의미, Docker라는 런타임을 이용해 pod 안의 컨테이너를 구성


- 컨트롤 플레인 컴포넌트 

- 클러스터에 관한 전반적인 결정(스케쥴링)을 수행
- 디플로이먼트  : replicas를 복제하는 요구 사항을 충족시키는 일
=> 충족되지 않을 때 새로운 pod를 생성해야 함

-- kube-apiserver

 

- API 서버는 쿠버네티스 API를 노출하는 쿠버네티스 컨트롤 플레인 컴포넌트
=> 컨트롤 플레인의 프론트 엔드에 위치
- API 서버의 주요 구현은 kube-apiserver
=> kube-apiserver는 확장되도록 디자인
=> kube-apiserver 인스턴스를 통해 더 많은 인스턴스를 배포해서 확장 가능

-- etcd

- 모든 클러스터 데이터를 담는 쿠버네티스 백엔드의 저장소 
- 일관성, 고가용성, key-value 저장소
- etcd 를 백엔드의 저장소로 사용한다면, 데이터를 백업하는 계획이 필요

-- kube-scheduler

- 노드가 배정되지 않은 새로 생성된 pod 감지
- 스케쥴을 결정하는 요소
=> 리소스(주로 메모리)를 고려하여 개별 및 총체적 요구사항, 하드웨어/소프트웨어 정책적 제약 등을 포함