[초보] docker swarm 으로 그누보드5 로드밸런싱 흉내내기. 정보
[초보] docker swarm 으로 그누보드5 로드밸런싱 흉내내기.본문
## docker swarm 으로 그누보드5 로드밸런스 흉내내기 흉내는 흉내일뿐. 실제 서비스에서 로드밸런싱(부하분산)의 문제는 웹서버 프로세스의 접속제한이나 DB 서버의 처리능력, 네트워크 대역폭, 디스크의 I/O 성능등 다양한 부분을 감안한 복잡한 작업이지만, 제가 그런건 잘 모르고 다만, 웹서버를 2 개이상 복수로 늘려서 웹접속을 늘려서 부하를 조정하는 .. 아주 단순한 차원에서, 도커 스웜에서 제공하는 로드밸런스 기능으로 그누보드5를 설치해 봤습니다. 192.168.219.160 docker-master # 도커 마스터(매니저) 192.168.219.184 docker-node1 # 도커 노동자1 일단, 서버 2 대로 테스트했습니다. 서버는 둘다 우분투리눅스 19.10이고, 기본 도커패키지 docker.io 를 사용하고 hostnamectl 명령어로 각각 호스트이름을 docker-master, docker-node1 으로 지정해 줬습니다. 그누보드5 운영환경은, 웹서버와 mysql DB 서버를 분리하고, DB 서버는 docker-master 에서 1개만 실행하고, 웹서버는 2개이상 실행해서 docker-master 와 docker-node1 에서 나누어 늘려나가게 했습니다. mysql DB 서버는 docker-master 서버의 /home/mysql_data 라는 디렉토리에 컨테이너 내부의 /var/lib/mysql 디렉토리를 볼륨 연결하고, 아파치 웹서버는 /home/gnuboard_data 에 전체 소스를 넣어서 역시 이 디렉토리를 볼륨으로 컨테이너 내부의 /var/www/html 에 웹루트로 연결했습니다. 그런데 문제는, 웹서버를 2대 이상 서버에 분산해서 실행하면, 웹루트의 소스를 동일하게 공유해야 하므로, 네트워크 파일시스템인 nfs 로 노드들 간에 마운트해서 동일한 /home/gnuboard_data 를 접근 하게 했습니다. 우선, 도커 스웜 개념 이해에 집중하기 위해서, 보안상 안좋겠지만 까다로운 방화벽이 있다면 미리 꺼두고, 그리고 파일 디렉토리 접근 퍼미션은 대충ㅜㅜ 했습니다. 그리고, 아래 명령들은 마스터 노드와 노동자노드를 각각 왔다가 갔다하면서 실행하는데 구분은, 프롬프트의 master 와 node1 단어를 보고 잘 구분해서 실행하시길. docker-node2, docker-node3 등으로 계속 새로운 노드를 추가시 아래 node1의 작업을 동일하게 합니다. 1. 사전 작업 우선 docker-master에서 DB 서버와 웹서버가 마운트할 디렉토리를 생성합니다. root 권한으로 해야해서 sudo 로 합니다. nonots@docker-master:~$ sudo mkdir /home/mysql_data nonots@docker-master:~$ sudo mkdir -p /home/gnuboard_data/data nonots@docker-master:~$ sudo chmod 707 /home/mysql_data/ nonots@docker-master:~$ sudo chmod 707 /home/gnuboard_data/ nonots@docker-master:~$ sudo chmod 707 /home/gnuboard_data/data/ 그리고 그누보드5 소스 전체를 여기에 복사해서 gnuboard_data에 넣어 줍니다. docker-node1 에서는 db서버 볼륨은 필요 없으므로 gnuboard_data 만 생성합니다. nonots@docker-node1:~/mydocker$ sudo mkdir /home/gnuboard_data nonots@docker-node1:~/mydocker$ sudo chmod 707 /home/gnuboard_data 그리고 docker-node1 의 /home/gnuboard_data 는 마스터에서 마운트하므로 항상 빈디렉토리이어야 합니다. 그리고 마스터에서 nfs 서버를 설치합니다. nonots@docker-master:~$ sudo apt-get install nfs-common nfs-kernel-server rpcbind portmap 그리고 /etc/exports 파일 제일 하단에 아래 1 줄 추가합니다. /home/gnuboard_data 192.168.219.184(rw,sync,no_subtree_check) 192.168.219.184(docker-node1)에서 /home/gnuboard_data 를 마운트 가능하게 하다는 뜻인데, 만약 node2, node3 와 같이 늘어난다면, 그 노드 아이피도 같이 동일하게 추가하면 됩니다. nonots@docker-master:~$ sudo exportfs -a nonots@docker-master:~$ sudo systemctl restart nfs-kernel-server 그후 위와 같이 해서 nfs-server 를 실행합니다. 이 nfs 는 111 와 2049 포트를 사용하는데, 추후 방화벽 실행시 이 포트를 열어 줘야 할겁니다. 그리고, 이제 docker-node1 에서는 nfs 클라이언트만 사용하므로 nonots@docker-node1:~$ sudo apt install nfs-common nonots@docker-node1:~$ sudo mount -t nfs 192.168.219.160:/home/gnuboard_data /home/gnuboard_data 위와 같이 docker-master(192.168.219.160) 에서 gnuboard_data 폴더를 nfs 로 마운트합니다. 만약, 서버 재시작시 자동으로 마운트 되게 하려면 /etc/fstab 에 지정해야 하는데, 그 방법은 알아서 각자. 이렇게 하면 nonots@docker-node1:~$ cd /home/gnuboard_data/ nonots@docker-node1:/home/gnuboard_data$ ls 하면 그누보드 전체소스가 보여야 정상. 그리고 나서, 모든 서버에서 도커데몬이 정상적으로 실행되어 있는지 확인합니다. 2. 사용할 도커 이미지 생성 웹서버는 아파치2.4에 php가 모듈로 지원되고, php-mysqli php-gd 같은 php 모듈도 사용 하기위해, hub.docker.com 에 있는 php:7.4-apache 라는 이미지를 불러와서 간단하게 다시 빌드를 했습니다. 이렇게 빌드한걸 hub.docker.com 에 nonots/gnudocker:v1 이라는 이름으로 등록을 해두었습니다. https://hub.docker.com/r/nonots/gnudocker 이제 docker pull nonots/gnudocker:v1 이라는 명령어로 어디서나 원격으로 사용가능하게 했습니다. 만약, 본인이 새로 이미지를 만들겠다면, 아래 Dockerfile 을 적절하게 수정해서 빌드를 해서 로컬에서 사용하면 됩니다. 그런데, 문제는 이렇게 로컬에 빌드하려면 master뿐만 아니라 다른 노드에도 모두 동일 이미지로 빌드를 해야 웹서버를 복제시 정상 작동하게 됩니다. nonots@nonots-master:~/mydocker$ cat Dockerfile ROM php:7.4-apache MAINTAINER nonots RUN apt update && apt -y install libfreetype6-dev libjpeg62-turbo-dev zlib1g-dev libpng-dev \ && docker-php-ext-configure gd --with-freetype --with-jpeg \ && docker-php-ext-install -j$(nproc) gd mysqli 위와 같이 3줄짜리 Dockerfile 를 간단하게 만듭니다. 그런후 아래와 같이 nonots/gnudocker:v1 이라는 이미지 이름으로 빌드를 합니다. nonots@nonots-master:~/mydocker$ docker build . -t nonots/gnudocker:v1 빌드가 성공하면 nonots@nonots-master:~/mydocker$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE nonots/gnudocker v1 78566041ec11 13 seconds ago 435MB 와 같이 이미지 목록에 보입니다. 3. docker swarm 모드 실행 우선 docker-master 에서 docker swarm init 명령어를 아래와 같이 실행합니다. nonots@docker-master:~/mydocker$ docker swarm init --advertise-addr 192.168.219.160 Swarm initialized: current node (j0m1pxp35cgd9ylu3aaaa3t2j) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-4m5w9f7sar3xq5xpx0lomsrveqqbm5qda723mi24i2rn8u0ebp-ebuk5n1rcxr21a0ddaln4c7dl 192.168.219.160:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions. 그러면 위 내용에서 토큰값을 사용하는 docker swarm join 명령줄이 나오는데, 이 명령어를 그대로 복사해서 각 노동자 노드에 실행하면 됩니다. 이 부분은 복사해서 저장해 두는게 좋습니다. docker-node1 에서 아래와 같이 실행하면, 그 노드는 swarm 패밀리에 포함됩니다. nonots@docker-node1:~$ docker swarm join --token SWMTKN-1-4m5w9f7sar3xq5xpx0lomsrveqqbm5qda723mi24i2rn8u0ebp-ebuk5n1rcxr21a0ddaln4c7dl 192.168.219.160:2377 This node joined a swarm as a worker. 마스터에서 노드 상태를 보면 아래와 같이 되어 있으면 정상입니다. 이제 본격적으로 로드밸런싱을 사용할수 있습니다. nonots@docker-master:~/mydocker$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION j0m1pxp35cgd9ylu3aaaa3t2j * docker-master Ready Active Leader 19.03.6 l0taqdgxz2bfcw65u8zqxbme2 docker-node1 Ready Active 19.03.8 3. 각 서비스 생성 우선 mysql DB 서비스(mymysql)를 생성 실행합니다. 이건 항상 제일먼저 생성해서 마스터 노드에서만 컨테이너가 위치하게 해야함. nonots@docker-master:~$ docker service create --name mymysql --replicas 1 \ --constraint 'node.role==manager' --mount type=bind,src=/home/mysql_data,dst=/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=root2349 -e MYSQL_USER=nonots -e MYSQL_DATABASE=nonots_db \ -e MYSQL_PASSWORD=kwon2349 -p 3306:3306 -d mysql:latest \ --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci 그누보드가 사용할 DB 정보를 nonots,nonots_db,kwon2349 로 생성합니다. nonots@docker-master:~$ docker service ls ID NAME MODE REPLICAS IMAGE PORTS 1kv5g06zn64z mymysql replicated 1/1 mysql:latest *:3306->3306/tcp nonots@docker-master:~/mydocker$ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 07e9a16b4bab mysql:latest "docker-entrypoint.s…" 8 seconds ago Up 7 seconds 3306/tcp, 33060/tcp mymysql.1.n6cdjbkvl0xeizy32ciwg9pl1 생성한 후 아래 명령어로 컨테이너 ID 값을 이용해서 mysql 접속시 mysql 프롬프트가 뜨면 정상입니다. nonots@docker-master:~$ docker container exec -it 07e9a16b4bab mysql -unonots -pkwon2349 nonots_db 그 다음에 아파치 웹서버 서비스(mygnu)를 생성 실행하는데 복제 갯수를 (--replicas 3) 3개 만들게 했습니다. nonots@docker-master:~$ docker service create --name mygnu --replicas 3 \ --mount type=bind,src=/home/gnuboard_data,dst=/var/www/html -p 8888:80 \ -d nonots/gnudocker:v1 이렇게 2 개 서비스를 생성하면 아래와 같이 서비스가 보여야 합니다. nonots@docker-master:~$ docker service ls ID NAME MODE REPLICAS IMAGE PORTS hu2sel7mozt2 mygnu replicated 3/3 nonots/gnudocker:v1 *:8888->80/tcp tgh1jvrqascz mymysql replicated 1/1 mysql:latest *:3306->3306/tcp 그리고 그중에서 웹서버 mygnu 는 아래와 같이 master 에 1개, node1 에 2 개가 생성되어 있습니다 nonots@docker-master:~$ docker service ps mygnu ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS knmz2tgjwkxo mygnu.1 nonots/gnudocker:v1 docker-master Running Running about a minute ago ax7unskk8an0 mygnu.2 nonots/gnudocker:v1 docker-node1 Running Running about a minute ago 7m9antdw76yi mygnu.3 nonots/gnudocker:v1 docker-node1 Running Running about a minute ago docker-master 에서 컨테이너를 보면 mygnu 1개와 mymysql 1개가 보이고 nonots@docker-master:~$ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 81e4fb7f162f nonots/gnudocker:v1 "docker-php-entrypoi…" About a minute ago Up About a minute 80/tcp mygnu.1.knmz2tgjwkxorhj2dt5zsyzq6 8d48664abbbb mysql:latest "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 3306/tcp, 33060/tcp mymysql.1.xk40f7u8n0ou83cw95pg5fkhq docker-node1 서버에서는 mygnu 2개가 보일겁니다. nonots@docker-node1:~$ docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6cd8f31238b1 nonots/gnudocker:v1 "docker-php-entrypoi…" 2 minutes ago Up About a minute 80/tcp mygnu.3.7m9antdw76yi2h362jy52rtzq d2a1e7cf43cd nonots/gnudocker:v1 "docker-php-entrypoi…" 2 minutes ago Up About a minute 80/tcp mygnu.2.ax7unskk8an0mk3fuktr1qkzh 이제 웹브라우저에서 http://192.168.219.160:8888 (http://192.168.219.184:8888로 해도 됨)으로 접속하면 그누보드 설치화면이 뜨게 됩니다. Mysql DB 정보 입력에서 Host 주소는 기본 localhost 가 아니라 mymysql 혹은 마스터IP 즉 192.168.219.160 둘 다 해도 되더군요. 게시판에 글을 몇개 등록해 봅니다. 이렇게 일단 웹서버가 작동하는건 알겠는데, 과연 로드밸런싱이 되는지 확인하려면 마스터 /home/gnuboard_data 디렉토리에 간단하게 아래와 같이 lb.php 를 만듭니다. nonots@docker-master:~$ cat /home/gnuboard_data/lb.php <?php echo $_ENV['HOSTNAME'] . ' - ' ; echo $_SERVER['SERVER_NAME'] . ' - '; echo $_SERVER['SERVER_ADDR']; ?> 그리고 웹브라우저에서 http://192.168.219.160:8888/lb.php 를 실행합니다. 시간이 지나서 새로고침을 해보고, 다른 브라우저로 위 주소를 열어 봅니다. 터미널에서 curl 로 테스트를 해보면 아래와 같이 실행시 마다 다른 웹서버를 연결함을 알수 있습니다. 즉 URL 은 동일하게 보여도, 도커 스웜에서 라운드로빈 방식으로 로드밸런스를 하고 있어서 특정 접속마다 자동으로 다른 웹서버에 접속이 됩니다. http://192.168.219.184:8888/lb.php 6cd8f31238b1 - 192.168.219.184 - 10.0.0.109 http://192.168.219.184:8888/lb.php d2a1e7cf43cd - 192.168.219.184 - 10.0.0.110 http://192.168.219.184:8888/lb.php 81e4fb7f162f - 192.168.219.184 - 10.0.0.108 http://192.168.219.184:8888/lb.php 6cd8f31238b1 - 192.168.219.184 - 10.0.0.109 이제 복제 갯수 늘리거나 줄여보겠습니다. 기존 3개에서 5개로 늘리면 nonots@docker-master:~$ docker service scale mygnu=5 mygnu scaled to 5 overall progress: 5 out of 5 tasks 1/5: running [==================================================>] 2/5: running [==================================================>] 3/5: running [==================================================>] 4/5: running [==================================================>] 5/5: running [==================================================>] verify: Service converged nonots@docker-master:~$ docker service ls ID NAME MODE REPLICAS IMAGE PORTS hu2sel7mozt2 mygnu replicated 5/5 nonots/gnudocker:v1 *:8888->80/tcp tgh1jvrqascz mymysql replicated 1/1 mysql:latest *:3306->3306/tcp 그런후에 각 노드에서 어떻게 웹서버가 분산되어 있는지 보면 아래와 같이 마스트에 2개, node1 에 3개로 각각 분산되어 추가됨을 알수 있습니다. nonots@docker-master:~$ docker node ps docker-master ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS knmz2tgjwkxo mygnu.1 nonots/gnudocker:v1 docker-master Running Running 12 minutes ago xk40f7u8n0ou mymysql.1 mysql:latest docker-master Running Running 13 minutes ago xyt8rdnbos5g mygnu.4 nonots/gnudocker:v1 docker-master Running Running about a minute ago nonots@docker-master:~$ docker node ps docker-node1 ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS ax7unskk8an0 mygnu.2 nonots/gnudocker:v1 docker-node1 Running Running 12 minutes ago 7m9antdw76yi mygnu.3 nonots/gnudocker:v1 docker-node1 Running Running 12 minutes ago 6jozbsc02pz0 mygnu.5 nonots/gnudocker:v1 docker-node1 Running Running about a minute ago 4. yaml 파일을 이용한 서비스 실행 이제 위에서 실행한 mygnu mymysql 서비스를 삭제해보겠습니다. nonots@docker-master:~$ docker service rm mygnu mymysql 너무 간단해서 허무하게 모든 컨테이너가 삭제되어 사라집니다. 그누보드도 사라졌습니다. 다시 시작하기 위해 위에서 실행한 docker service create 의 기다란 명령어를 실행해되 되지만, 대신 이번에는 yaml 파일을 이용해서 한 큐에 해보겠습니다 nonots@docker-master:~/mydocker$ cat stack.yaml version: "3" services: mymysql: image: mysql:latest ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: "root2349" # MYSQL root패스워드 설정 옵션 MYSQL_USER: "nonots" # 그누보드 사용자 MYSQL_DATABASE: "nonots_db" # 그누보드 사용 DB MYSQL_PASSWORD: "kwon2349" #그누보드 비번 command: # 명령어 실행 - --character-set-server=utf8mb4 - --collation-server=utf8mb4_unicode_ci volumes: - "/home/mysql_data:/var/lib/mysql" deploy: replicas: 1 placement: constraints: - "node.role==manager" mygnu: #apache php 웹서버 image: nonots/gnudocker:v1 ports: - "8888:80" volumes: - "/home/gnuboard_data:/var/www/html" deploy: replicas: 3 위와 같은 stack.yaml 파일을 만든 후 아래와 같이 docker stack deploy 명령어로 sir 이라는 이름의 스택을 생성합니다. nonots@docker-master:~/mydocker$ docker stack deploy -c ./stack.yaml sir Creating network sir_default Creating service sir_mymysql Creating service sir_mygnu 그러면, 자동으로 서비스명이 sir_ 가 붙어서 실행됩니다. (주의:만약 그노보드 초기 설치라면 mysql host 란에 sir_mymysql 을 입력) nonots@docker-master:~/mydocker$ docker stack ls NAME SERVICES ORCHESTRATOR sir 2 Swarm nonots@docker-master:~/mydocker$ docker stack ps sir ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS i174wfc3e0z9 sir_mygnu.1 nonots/gnudocker:v1 docker-node1 Running Running 7 seconds ago jqhx57uy58h5 sir_mymysql.1 mysql:latest docker-master Running Running 18 seconds ago 6g30kt5bmt5n sir_mygnu.2 nonots/gnudocker:v1 docker-node1 Running Running 8 seconds ago w4slrrr5d0cs sir_mygnu.3 nonots/gnudocker:v1 docker-master Running Running 14 seconds ago nonots@docker-master:~/mydocker$ docker service ls ID NAME MODE REPLICAS IMAGE PORTS 6wybc9w12gfw sir_mygnu replicated 3/3 nonots/gnudocker:v1 *:8888->80/tcp qss522ijv5rp sir_mymysql replicated 1/1 mysql:latest *:3306->3306/tcp 위와 같이 웹서버(sir_mygnu) 3개와 sir_mymysql 1개가 실행되고, 웹브라우저로 접속하면 기존 설치한 그누보드 정보와 DB 정보가 그대로 남아있음을 알게 됩니다. 만약, 서비스 종료시에는 nonots@docker-master:~$ docker stack rm sir Removing service sir_mygnu Removing service sir_mymysql Removing network sir_default 와 같이 역시 한번에 모든 서비스가 종료 됩니다. 클라우드 환경이 만들고 있는 이런 마이크로서비스 세계의 가벼움에서 민첩함과 허망함이 섞여 느껴집니다.
추천
2
2
댓글 0개