Docker 개인 Project - JDSS 개발 내용

Jaehong Lee·2022년 8월 29일

Project 개발 내용

목록 보기
2/2
post-thumbnail

1. JDSS 목표

JDSS 는 Jaehong Docker Swarm Service 의 준말이다
개발 파일 ) https://github.com/lijahong/Docker_JDSS_Project

모니터링 환경

  • 위와 같이 Metrice Api 를 활용하여 Grafana & Prometheus & cAdvisor 를 이용한 모니터링 환경을 구축한다

사용자 맞춤 Stack 배포 프로그램

2. Harbor 구축

오픈소스 컨테이너 레지스트리 도구인 Harbor 를 이용하여 사설 레지스트리를 구현하자

Harbor 설치

참조 ) https://judo0179.tistory.com/72
참조 ) https://smoh.tistory.com/328?category=736086

  • https 을 이용한 ssl 인증서 사용 방식이 아닌, http 를 이용해 username 과 password 를 이용한 방식 사용, https 설정은 주석처리함
# 설치 파일 다운로드
wget https://github.com/goharbor/harbor/releases/download/v1.10.1/harbor-offline-installer-v1.10.1.tgz

# 설치 파일 압축 해제
tar -xvf harbor-offline-installer-v1.10.1.tgz

# harbor 설정 - http 를 사용하므로 https 부분을 주석처리 하였다
cd harbor
vi harbor.yml

# 설치
sudo ./install.sh

Harbor 설치 확인

  • 잘 설치가 됬다면, Node 의 Ip 주소를 통해 Harbor 에 접속해주자
  • Harbor 의 Repository 단위는 Project 이다. Project 를 생성해주자
  • 다른 Node 들에서 Harbor 에 로그인 해주자

3. 모니터링 환경 구축

  • Prometheous & Grafana 를 이용하여 Node 및 Container 환경을 모니터링해보자

    metric Api 를 이용한 Pull 방식을 사용한다

node-exporter & cAdvisor 설치

Worker Node 들에 배포한다. 이를 통해 Manager Node 의 Prometheus 에서 Data 를 Pull 할 수 있다

참조 ) https://m.blog.naver.com/PostView.nhn?blogId=alice_k106&logNo=221090348538&proxyReferer=https:%2F%2Fwww.google.com%2F

# node-exporter 배포
docker run -d -p 9100:9100 --restart always --name node-exporter prom/node-exporter:v0.14.0

# cAdvisor 배포
docker run --volume=/:/rootfs:ro  --volume=/var/run:/var/run:rw  --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  --restart always google/cadvisor:v0.27.0

prometheus & grafana 배포

Manager Node 에 배포한다. 이를 통해 Manager Node 에서 Cluster 환경에 Join 된 Worker Node 들을 모니터링 할 수 있다

참조 ) https://m.blog.naver.com/PostView.nhn?blogId=alice_k106&logNo=221090348538&proxyReferer=https:%2F%2Fwww.google.com%2F

prometheus yml 구현

global:
    scrape_interval: 15s
    external_labels:
        monitor: 'cadvisor-monitor'
scrape_configs:
    - job_name: 'cadvisor-exporter'
      static_configs:
          - targets: ['211.183.3.101:8080', '211.183.3.102:8080']
  • cAdvisor 의 Data 를 Pull 할 prometheus Container 이다. target 으로 8080 Port 를 지정하여 cAdvisor 와 연동하게 설정한다
global:
    scrape_interval: 15s
    external_labels:
        monitor: 'node-monitor'

scrape_configs:
    - job_name: 'node-exporter'
      static_configs:
          - targets: ['211.183.3.101:9100', '211.183.3.102:9100']
  • node exporter 의 Data 를 Pull 할 prometheus Container 이다. target 으로 9100 Port 를 지정하여 node exporter 와 연동하게 설정한다

Prometheus & Grafana 배포

# node-exporter 의 Data 를 수집하는 prometheus 배포
docker run -d --name prometheus_node --restart always -h prometheus_node -v $(pwd)/prome-node.yml:/etc/prometheus/prometheus.yml prom/prometheus:v1.7.0 -config.file=/etc/prometheus/prometheus.yml

# cAdvisor 의 Data 를 수집하는 prometheus 배포
docker run -d --name prometheus_cadvisor --restart always -h prometheus_cadvisor -v $(pwd)/prome-cad.yml:/etc/prometheus/prometheus.yml prom/prometheus:v1.7.0 -config.file=/etc/prometheus/prometheus.yml

# Grafana 배포
docker run -d --name grafana -h grafana --restart always -e GF_SECURITY_ADMIN_PASSWORD=test123 -p 3000:3000 --link prometheus_cadvisor:prome_cad --link prometheus_node:prome_node grafana/grafana:4.4.3

Grafana Setting

Grafana 는 API 방식을 통해 Prometheus 의 Data 를 가져온다. 따라서 Grafana 에서 Prometheus 에서 수집한 Data 를 모니터링하려면, Prometheus 의 Ip 주소를 입력해줘야 한다

Data Source Setting

  • Name 은 식별만 할 수 있으면 된다
  • Type 은 Prometheus 로 설정해주자
  • Http settings 에는 접속하고자 하는 Prometheus Container 의 주소를 입력해주자. 우리는 Grafana 배포시 link 를 해주었으므로 Prometheus Container 의 이름을 입력해주면, 자동으로 자신의 Hosts 파일에서 해당 Ip 주소를 찾아준다. Port 는 Prometheus Default Port 인 9090 Port 를 사용한다

  • cAdvisor 에 대응하는 Prometheus Container 도 Grafana 와 연동해주자

Dashboard Setting

Data Source 를 통해 가져온 Data 를 시각화 해줘야 한다. 이를 Dashboard 를 통해 Customize 및 조회가 가능하다

  • 위와 같이 다른 사용자가 제공하는 json 파일을 Import 해줄 수 있다
  • Name 과 해당 Dashboard 에 대응하는 Data Source 를 선택해주자

  • cAdvisor 로부터 수집한 Data 를 모니터링 할 수 있다!
  • node exporter 로부터 수집한 Data 역시 모니터링이 가능하다

사용자 맞춤 Stack 배포 프로그램 파일 구조

각 Directory 설명

4. Dockerfile 구현

  • Dockerfile 은 위와 같은 구조이다. httpd 와 nginx Image 를 Build 하기 위해 각각 Directory 를 생성하여 안에 Dockerfile 을 구현하였다

httpd Dockerfile

FROM httpd
ADD index.html /usr/local/apache2/htdocs/index.html
  • httpd 에 사용자 지정 Web page 를 넣어주게 구현

nginx Dockerfile

FROM nginx
ADD index.html /usr/share/nginx/html/index.html
  • nginx 도 동일하게 Build 하도록 구현한다

5. Stack.yml 구현

  • yml 을 위와 같은 구조이다. 각각 httpd & HAproxy / nginx & HAproxy / wordpress & mysql & HAproxy 를 STACK 배포해주기 위한 yml 파일이다

httpd_service_base.yml

version: '3.7'

services:
  httpd:
    image: 211.183.3.103:80/jdss_repo/setname_httpd:v1
    deploy:
      replicas: set_replicas
      placement:
        constraints: [node.role == worker]
      restart_policy:
        condition: on-failure
        max_attempts: 2
    environment:
      SERVICE_PORTS: 80
    networks:
      - set_network

  proxy:
    image: dockercloud/haproxy
    depends_on:
      - httpd
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    ports: # attach on ingress network 1
      - 80
    networks: # attach on web network 2 - nginx connect
      - set_network
    deploy:
      mode: global
      placement:
        constraints: [node.role == manager]
      restart_policy:
        condition: on-failure
        max_attempts: 2

networks:
  set_network:
    external: true
  • worker node 에는 httpd, manager node 에는 HAproxy 를 배포하여, manager node 의 HAproxy 에 접속시 생성되는 Overlay Network 를 통해 httpd 에 접속하게 해준다

nginx_service_base.yml

version: '3.7'

services:
  nginx:
    image: 211.183.3.103:80/jdss_repo/setname_nginx:v1
    deploy:
      replicas: set_replicas
      placement:
        constraints: [node.role == worker]
      restart_policy:
        condition: on-failure
        max_attempts: 2
    environment:
      SERVICE_PORTS: 80
    networks:
      - set_network

  proxy:
    image: dockercloud/haproxy
    depends_on:
      - nginx
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    ports: # attach on ingress network 1
      - 80
    networks: # attach on web network 2 - nginx connect
      - set_network
    deploy:
      mode: global
      placement:
        constraints: [node.role == manager]
      restart_policy:
        condition: on-failure
        max_attempts: 2

networks:
  set_network:
    external: true
  • worker node 에는 nginx, manager node 에는 HAproxy 를 배포하여, manager node 의 HAproxy 에 접속시 생성되는 Overlay Network 를 통해 nginx 에 접속하게 해준다

wp_service_base.yml

version: '3.7'
services:
  wordpress:
    image: wordpress
    networks:
      - setname
    depends_on:
      - db
    environment:
      WORDPRESS_DB_PASSWORD: test123
      WORDPRESS_DB_USER: root
      WORDPRESS_DB_NAME: testdb
      WORDPRESS_DB_HOST: db:3306
      SERVICE_PORTS: 80
    deploy:
      replicas: set_replicas
      placement:
        constraints: [node.role == worker]
      restart_policy:
        condition: on-failure
        max_attempts: 2

  db:
    image: mysql:5.7
    networks:
      - setname
    volumes:
      - dbvol:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: test123
      MYSQL_DATABASE: testdb
    deploy:
      mode: global
      placement:
        constraints: [node.role == manager]
      restart_policy:
        condition: on-failure
        max_attempts: 2

proxy:
    image: dockercloud/haproxy
    depends_on:
      - wordpress
      - db
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    ports: # attach on ingress network 1
      - 80
    networks: # attach on web network 2 - nginx connect
      - setname
    deploy:
      mode: global
      placement:
        constraints: [node.role == manager]
      restart_policy:
        condition: on-failure
        max_attempts: 2


networks:
  setname:
    external: true
volumes:
  dbvol:
  • manager node 에 HAproxy 와 mysql 을 설치해준다. manager node 의 HAproxy 에 접속시 생성되는 Overlay Network 를 통해 wordpress 에 접속하게 한다
  • manager node 의 Mysql 과 worker node 들의 wordpress 를 연결하여 HAproxy 에서 어떤 wordpress 에 접속하게 해도, Data 를 동일하게 해준다

6. Scripts 구현

  • Scripts 는 위와 같이 구성된다
  • Scripts 들은 주로 Stack 배포 기능을 정의한다
    • nginx & httpd 배포시 makeweb.sh 를 실행하며, nginx 와 httpd 에 따라 각각의 createstack.sh 가 실행된다
    • wordpress 배포시 makewp.sh 가 실행되어 Stack 을 배포한다
    • main 에는 주 Dialog 와 STACK 조회 & 삭제 & 생성 이 정의되어 있다
      • nginx & httpd & wordexpress 는 각각 사용자에게 입력받는 Data 가 다르므로, Dialog 후반부는 makeweb.sh 와 makewp.sh 에 구현되어 있다

main

#!/bin/bash

#create temp file
selectmenu=$(mktemp -t test.XXX) #menu select - main
stacklist=$(mktemp -t test.XXX) #contain stack ls list - showlist
stackselect=$(mktemp -t test.XXX) #selected stack - showlist
stackname_temp=$(mktemp -t test.XXX) #STACK NAME - CREATE
stackservice_temp=$(mktemp -t test.XXX) #Service name - CREATE
stackreplicas_temp=$(mktemp -t test.XXX) #REPLICAS NUMBER - CREATE

#show stack & service list
showlist(){
	#get stack ls list by file
	count=$[ 0 + 1 ]
	echo "" > $stacklist
	docker stack ls | while read line
	do
		#except column name
        	if [ $count -gt 1 ]
        	then
                	name=$(echo $line | grep -v NAME | gawk {'print $1'})
                	service=$(echo $line | grep -v NAME | gawk {'print "SERVICE=" $2 "==ORCHESTRATOR=" $3'})
			#modify for radiolist
                	echo "$name '$service' OFF" >> $stacklist
        	fi
        	count=$[ $count + 1 ]
	done
	#get variable for stack list file
	stackstr=$(cat $stacklist)
	#radio list for stack
	dialog --title "STACK LIST" --radiolist "CHOOSE STACK FOR FIND SERVICES" 15 50 0 $stackstr 2>$stackselect
	if [ $? -eq 0 ] #if you choose ok
	then
		#if user do wrong usement -> select file is empty
		if [ ! -s $stackselect ]
		then
			dialog --title "WRONG USEMENT" --msgbox "Input Method is space -> enter" 8 20
		else
			#get service list for choose stack
        		servicelist=$(mktemp -t test.XXX) #get docker stack ps result file
       	 		stackname=$(cat $stackselect)
        		docker stack ps $stackname > $servicelist
        		dialog --title "$stackname Service" --textbox $servicelist 0 0
			if [ $? -eq 0 ]
			then
				network_ip=$(docker network inspect $stackname | grep Subnet | gawk {'print $2'} | tr -d ',' | tr -d '"')
                        	network_subnet=$(docker network inspect $stackname | grep Gateway | gawk {'print $2'} |  tr -d '"')
                        	network_scope=$(docker network inspect $stackname -f "{{.Scope}}")
                        	network_driver=$(docker network inspect $stackname -f "{{.Driver}}")
                        	host_port=$(docker service inspect ${stackname}_proxy -f "{{.Endpoint.Ports"}} | gawk '{print $4}')
I
                        	dialog --title "STACK INFORMATION" --msgbox "$stackname Information \n Network Ip : $network_ip \n Network Subnet : $network_subnet \n Network_Scope : $network_scope \n Network Driver : $network_driver \n Access Port : $host_port" 10 50

			fi

        		rm -rf $servicelist 2> /dev/null
		fi
	fi
}

#delect stack function
deletestack(){
	count=$[ 0 + 1 ]
        echo "" > $stacklist
        docker stack ls | while read line
        do
                #except column name
                if [ $count -gt 1 ]
                then
                        name=$(echo $line | grep -v NAME | gawk {'print $1'})
                        service=$(echo $line | grep -v NAME | gawk {'print "SERVICE=" $2 "==ORCHESTRATOR=" $3'})
                        #modify for radiolist
                        echo "$name '$service' OFF" >> $stacklist
                fi
                count=$[ $count + 1 ]
        done
        #get variable for stack list file
        stackstr=$(cat $stacklist)
        #radio list for stack
        dialog --title "DELETE STACK" --radiolist "CHOOSE STACK FOR DELETE" 15 50 0 $stackstr 2>$stackselect
        if [ $? -eq 0 ] #if you choose ok
        then
		#if user do wrong usement -> select file is empty
                if [ ! -s $stackselect ]
                then
                        dialog --title "WRONG USEMENT" --msgbox "Input Method is space -> enter" 8 20
                else
			#SHOW CONFIRM MENU FOR DELETE -> file content is exist
               	 	stackname=$(cat $stackselect)
			dialog --title "Delete Confirm" --yesno "ARE YOU SURE FOR DELETE STACK - $stackname ?" 10 50
		
			#IF YOU CHOOSE OK
			if [ $? -eq 0 ] 
			then
				#Delete selected stack & overlay network
				docker stack rm $stackname > /dev/null
				docker network rm $stackname > /dev/null

				#if service is wordpress, then remove volume too
				iswordpress=$(docker volume ls | grep $stackname)
				if [ -n "$iswordpress"  ]
				then
					dialog --title "Volume Delete" --msgbox "Volume for Mysql will remove" 10 50
					sleep 10
					docker volume rm -f ${stackname}_dbvol
				fi

				if [ $? -eq 0 ]
				#if delect is complete well, show confirm message
				then
					dialog --title "Delete Confirm" --msgbox "$stackname STACK DELETE COMPLETE" 10 50
				fi

			fi
		fi
        fi

}

stackcreate(){
	
	dialog --title "STACK NAME" --inputbox "Pls Input Stack Name : " 10 50 2>$stackname_temp
	stack_name=$(cat $stackname_temp)
	if [[ $? -eq 0 ]] && [[ -n $stack_name ]]
	then
		dialog --title "Select Service" --radiolist "Pls Select Deploy Service" 10 80 0 "nginx" "WEB Service by nginx & HAproxy" ON "httpd" "WEB Service by httpd & HAproxy" OFF "wordpress" "Blog Service by wordpress & mysql & HAproxy" OFF 2> $stackservice_temp
		choice=$(cat $stackservice_temp) #user choice service
		if [[ $? -eq 0 ]] && [[ -n $choice ]]
		then
			dialog --title "REPLICAS" --radiolist "Pls Select Replicas Number" 10 50 0 1 "replicas=1" ON 2 "replicas=2" OFF 3 "replicas=3" OFF 4 "replicas=4" OFF 5 "replicas=5" OFF 6 "replicas=6" OFF 2>$stackreplicas_temp
			stack_replicas=$(cat $stackreplicas_temp)

			if [[ $? -eq 0 ]] && [[ -n $stack_replicas ]]
			then
				#if user choice web service nginx or http
				if [[ "$choice" == "nginx" ]] || [[ "$choice" == "httpd" ]]
				then
					/home/rapa/jdss/scripts/makeweb.sh $stack_name $stack_replicas $choice
				elif [[ "$choice" == "wordpress" ]]
				then
					/home/rapa/jdss/scripts/makewp.sh $stack_name $stack_replicas $choice
				fi
			fi
		fi
	fi
}

#menu start
while [ 1 ]
do
        # 메인메뉴 출력하기
        dialog --menu "JDSS SERIVE" 20 40 8 1 "SHOW LIST" 2 "DELETE STACK" 3 "CREATE STACK" 0 "종료" 2> $selectmenu
        # 종료코드 확인하여 cancel 이면 프로그램 종료
        if [ $? -eq 1 ]
        then
                break
        fi

        selection=$(cat $selectmenu)
        case $selection in
        1)
                showlist ;;
        2)
                deletestack ;;
        3)
                stackcreate ;;
        0)
                break ;;
        *)
                dialog --msgbox "WRONG SELECT MENU - Pls SELECT EXIST MENU NUMBER" 10 40
        esac
done

#delect temp file
rm -rf $selectmenu 2> /dev/null
rm -rf $stacklist 2> /dev/null
rm -rf $stackselect 2> /dev/null
rm -rf $stackname_temp 2> /dev/null
rm -rf $stackservice_temp 2> /dev/null
rm -rf $stackreplicas_temp 2> /dev/null

main 기능

  1. main 메뉴 Dialog
  2. STACK list 및 세부 정보 조회
  3. STACK 삭제
    • 삭제할 STACK 이 wordpress Service 라면, 해당 Mysql 과 mount 된 Manager node 의 Volume 도 삭제해준다
    • STACK 에서 사용하는 Overlay Network 도 삭제한다
  4. STACK 생성
    • 생성할 STACK 이름 & Replicas & 생성할 Service 종류를 선택하여 Service 종류 별로 해당 생성 Script 파일에 매개변수로 사용자 입력 Data 를 넘겨주어 실행한다

makeweb.sh

#!/bin/bash

# $1 is name $2 is replicas $3 is choice
#create temp file
gitaddr_temp=$(mktemp -t test.XXX)
                                
#input git addr
dialog --title "Git Repository" --inputbox "Pls Input Git Repositoy address, where index.html exist" 10 50 2>$gitaddr_temp
git_addr=$(cat $gitaddr_temp)
if [[ $? -eq 0 ]] && [[ -n $git_addr ]]
then
	#last confirm before deploy
	dialog --title "Information Confirmation" --yesno "Pls Confirm your Selection before deploy\n Stack name : $1 \n Service : $3 \n Stack replicas : $2 \n git address : $git_addr " 10 70
	if [ $? -eq 0 ]
	then
        	if [[ "$3" == "nginx" ]]
                then
                /home/rapa/jdss/scripts/makenginx/createstack.sh $1 $2 $git_addr > /dev/null
               
		elif [[ "$3" == "httpd" ]]
		then
	        /home/rapa/jdss/scripts/makehttpd/createstack.sh $1 $2 $git_addr > /dev/null
                fi
		if [ $? -eq 0 ]
                then
                	#get STACK INFORMATION

                	network_ip=$(docker network inspect $1 | grep Subnet | gawk {'print $2'} | tr -d ',' | tr -d '"')
                	network_subnet=$(docker network inspect $1 | grep Gateway | gawk {'print $2'} |  tr -d '"')
                	network_scope=$(docker network inspect $1 -f "{{.Scope}}")
                	network_driver=$(docker network inspect $1 -f "{{.Driver}}")
                	host_port=$(docker service inspect ${1}_proxy -f "{{.Endpoint.Ports"}} | gawk '{print $4}')
I
                	#show STACK INFORMATION
                	dialog --title "WORK COMPLETE" --msgbox "STACK DEPLOY COMPLETE\n Network Ip : $network_ip \n Network Subnet : $network_subnet \n Network_Scope : $network_scope \n Network Driver : $network_driver \n Access Port : $host_port" 10 80

                fi

        fi

fi

#delete Temp file
rm -rf $gitaddr_temp 2> /dev/null

makeweb.sh 기능

  1. Web Service 에 출력할 web page 를 불러올 git 주소를 받아와 clone
  2. 사용자 입력 사항을 출력해주고, 배포 최종 확인
  3. nginx 와 httpd 에 따라 Stack 배포 Script 실행
  4. STACK 배포시 해당 STACK 의 network 정보를 가져와서 dialog 로 출력

makewp.sh

#!/bin/bash
# $1 is name $2 is replicas
#last confirm before deploy

dialog --title "Information Confirmation" --yesno "Pls Confirm your Selection before deploy\n Stack name : $1 \n Service : $3 \n Stack replicas : $2 \n " 10  50
if [ $? -eq 0 ]
then
	cp /home/rapa/jdss/ymls/wp_service_base.yml /home/rapa/jdss/ymls/wp_service.yml
	sed -i "s/setname/$1/g" /home/rapa/jdss/ymls/wp_service.yml
	sed -i "s/set_replicas/$2/" /home/rapa/jdss/ymls/wp_service.yml

	if [ $? -eq 0 ]
	then
        	#docker network create - overlay

        	docker network create -d overlay $1 > /dev/null

        	#docker stack deploy

        	docker stack deploy -c /home/rapa/jdss/ymls/wp_service.yml --with-registry-auth $1 > /dev/null
		#notify mysql information
		dialog --title "DB INFORMATION" --msgbox " USER : root \n PASSWORD : test123 \n DB NAME : testdb \n " 10 40
                #Delete created file and image
                rm -rf /home/rapa/jdss/ymls/wp_service.yml
		if [ $? -eq 0 ]
                then
                #get STACK INFORMATION

                network_ip=$(docker network inspect $1 | grep Subnet | gawk {'print $2'} | tr -d ',' | tr -d '"')
                network_subnet=$(docker network inspect $1 | grep Gateway | gawk {'print $2'} |  tr -d '"')
                network_scope=$(docker network inspect $1 -f "{{.Scope}}")
                network_driver=$(docker network inspect $1 -f "{{.Driver}}")
                host_port=$(docker service inspect ${1}_proxy -f "{{.Endpoint.Ports"}} | gawk '{print $4}')
I
                #show STACK INFORMATION
                dialog --title "WORK COMPLETE" --msgbox "STACK DEPLOY COMPLETE\n Network Ip : $network_ip \n Network Subnet : $network_subnet \n Network_Scope : $network_scope \n Network Driver : $network_driver \n Access Port : $host_port" 10 80

                fi

	fi

fi

makewp.sh 기능

  1. 사용자 입력 사항을 출력해주고, 배포 최종 확인
  2. STACK 배포 yml 파일을 복사하여 사용자 입력 사항을 sed 을 통해 변경
  3. Overlay Network 생성
  4. STACK 배포
  5. STACK 배포시 해당 STACK 의 network 정보를 가져와서 dialog 로 출력
  6. 복사하여 사용한 yml 파일 삭제

makehttp/createstack.sh

#!/bin/bash

#creake dir for git clone and get index.html from git
mkdir /home/rapa/jdss/webpage/$1
git clone --quiet $3 /home/rapa/jdss/webpage/$1/ > /dev/null

#it goes to dir, where Dockerfile exist

cp /home/rapa/jdss/webpage/$1/index2.html /home/rapa/jdss/dockerfile_dir/httpd/index.html

#login
docker login 211.183.3.103:80 -uadmin -ptest123 > /dev/null 2>&1

#image build and push

docker build -t 211.183.3.103:80/jdss_repo/${1}_httpd:v1 /home/rapa/jdss/dockerfile_dir/httpd/.
docker push 211.183.3.103:80/jdss_repo/${1}_httpd:v1

#modify stack yml file
cp /home/rapa/jdss/ymls/httpd_service_base.yml /home/rapa/jdss/ymls/httpd_service.yml
sed -i "s/setname/$1/" /home/rapa/jdss/ymls/httpd_service.yml
sed -i "s/set_network/$1/g" /home/rapa/jdss/ymls/httpd_service.yml
sed -i "s/set_replicas/$2/" /home/rapa/jdss/ymls/httpd_service.yml

if [ $? -eq 0 ]
then
        #docker network create - overlay

        docker network create -d overlay $1

        #docker stack deploy

        docker stack deploy -c /home/rapa/jdss/ymls/httpd_service.yml --with-registry-auth $1
        if [ $? -eq 0 ]
        then
                #Delete created file and image

                rm -rf /home/rapa/jdss/ymls/httpd_service.yml
                rm -rf /home/rapa/jdss/webpage/$1
                rm -rf /home/rapa/jdss/dockerfile_dir/httpd/index.html
                docker image rm 211.183.3.103:80/jdss_repo/${1}_httpd:v1

        fi
fi

makehttp/createstack.sh 기능

  1. webpage Directory 에 git clone 해줄 Directory 를 생성하여 clone
  2. git clone 을 통해 가져온 index.html 을 사용할 Image 를 build 할 Dockerfile 의 Directory 로 이동
  3. Image Build 후 Harbor 에 Push
  4. 사용자 입력 사항에 맞게 httpd Stack 을 배포할 yml 파일을 복사하여 내용 변경
  5. 사용할 Overlay Network 생성
  6. Stack 배포
  7. 배포 성공시 복사하여 사용한 yml 파일 & git clone 한 Directory & 사용한 index.html & Build 한 Image 를 삭제

makenginx/createstack.sh

#!/bin/bash

#creake dir for git clone and get index.html from git
mkdir /home/rapa/jdss/webpage/$1
git clone --quiet $3 /home/rapa/jdss/webpage/$1/ > /dev/null

#it goes to dir, where Dockerfile exist

cp /home/rapa/jdss/webpage/$1/index.html /home/rapa/jdss/dockerfile_dir/nginx/index.html

#login
docker login 211.183.3.103:80 -uadmin -ptest123 > /dev/null 2>&1

#image build and push

docker build -t 211.183.3.103:80/jdss_repo/${1}_nginx:v1 /home/rapa/jdss/dockerfile_dir/nginx/.
docker push 211.183.3.103:80/jdss_repo/${1}_nginx:v1

#modify stack yml file
cp /home/rapa/jdss/ymls/nginx_service_base.yml /home/rapa/jdss/ymls/nginx_service.yml
sed -i "s/setname/$1/" /home/rapa/jdss/ymls/nginx_service.yml
sed -i "s/set_network/$1/g" /home/rapa/jdss/ymls/nginx_service.yml
sed -i "s/set_replicas/$2/" /home/rapa/jdss/ymls/nginx_service.yml

if [ $? -eq 0 ]
then
	#docker network create - overlay

	docker network create -d overlay $1

	#docker stack deploy

	docker stack deploy -c /home/rapa/jdss/ymls/nginx_service.yml --with-registry-auth $1
	if [ $? -eq 0 ]
	then
		#Delete created file and image

		rm -rf /home/rapa/jdss/ymls/nginx_service.yml
		rm -rf /home/rapa/jdss/webpage/$1 
		rm -rf /home/rapa/jdss/dockerfile_dir/nginx/index.html
		docker image rm 211.183.3.103:80/jdss_repo/${1}_nginx:v1 

	fi
fi

makenginx/createstack.sh 기능

  1. webpage Directory 에 git clone 해줄 Directory 를 생성하여 clone
  2. git clone 을 통해 가져온 index.html 을 사용할 Image 를 build 할 Dockerfile 의 Directory 로 이동
  3. Image Build 후 Harbor 에 Push
  4. 사용자 입력 사항에 맞게 httpd Stack 을 배포할 yml 파일을 복사하여 내용 변경
  5. 사용할 Overlay Network 생성
  6. Stack 배포
  7. 배포 성공시 복사하여 사용한 yml 파일 & git clone 한 Directory & 사용한 index.html & Build 한 Image 를 삭제

7. 기억나는 Error 들과 해결법

2 일이라는 시간 동안 Project 를 완수하였다. 이 개발 과정이 순탄했다고 하면 거짓말이다. 마지막으로 개발 과정 중 기억나는 Error 에 대해 알아보자

1. wordpress 와 HAproxy 연결 문제

  • wordpress 와 HAproxy 를 Stack 으로 같이 배포했음에도 HAproxy 가 wordpress 에 트래픽을 전달 못하는 문제가 있었다. Network 문제도 아니고, 각 Container 에도 문제가 없어서 고민하던 찰나, Port 와 Image 문제임을 추측하였다

해결법

  1. 사용한 Image 파일들의 tag가 none 으로 되어있는 것을 확인하고, Image 파일이 정상적이지 않다는 것을 확인하여, Image 를 Node 에 직접 Pull 하여 배포에 사용했다
  2. wordpress 의 Service Port 에 문제가 있는가 싶어서 환경 변수를 추가하였다

    • SERVICE_PORTS : 80 을 추가하여, HAproxy 가 wordpress 의 80 번 Port 를 통해 연결되게 설정하였다

2. wordpress 와 Mysql 연결 문제

  • error establishing a database connection , wordpress 배포시 흔하게 보이는 Error 이다. Mysql 과 wordpress 의 환경 변수에 오타가 있나 확인했지만, 오타는 없었다. 따라서, STACK 배포시, 서로 다른 Node 에 위치한 두 Container 간의 연결에 문제가 있지 않을까 해서 추가해야할 환경 변수의 존재를 추측하였다

해결법

  1. Stack 배포시 worker node 에 배포된 wordpress 들이 manager node 의 Mysql 을 찾지 못할까라는 추측에서 해결법을 생각해보았다. 두 Service 는 같은 Overlay Network 에 연결되있으니 통신이 가능하고, link 또한 되있으니 서로의 Ip 를 알고 있지 않을까 하였다
  2. 환경 변수에 WORDPRESS_DB_HOST: db:3306 을 추가하여, db 의 Ip 주소는 link 를 통해 hosts 파일에 적혀있으므로, 이를 참조하여 Mysql Container 의 3306 Port 와 연결되게 설정했다

3. wordpress 삭제시 Volume 삭제 안되는 문제

  • 원래 Stack 을 통해 생성한 Volume 은 Stack 삭제시 같이 삭제되야 정상이다. 허나, Mysql 과 Mount 한 manager node 의 Host Volume 이 삭제되지 않았다. 이를 직접 삭제해야 한다고 생각했다. 허나, Stack 삭제 후 일정 시간동안 Volume 은 Service 에서 사용하고 있다고, 삭제가 불가능했다

해결법

#if service is wordpress, then remove volume too
iswordpress=$(docker volume ls | grep $stackname)
if [ -n "$iswordpress"  ]
then
	dialog --title "Volume Delete" --msgbox "Volume for Mysql will remove" 10 50
	sleep 10
	docker volume rm -f ${stackname}_dbvol
fi
  1. nginx 나 httpd 배포시 Volume 을 사용하지 않는다. 따라서, 선택된 STACK 의 이름을 통해 Volume 이 있다면, wordpress STACK 이라고 판단하여 Volume 을 삭제하게 구현했다
  2. STACK 삭제 후 Volume 이 삭제될 수 있게 10 초 동안 대기 후 삭제하게 구현했다

4. dialog 절차 문제

  • dialog 진행시 cancel 을 선택하거나, Data 를 입력하지 않을 때도 다음 단계로 넘어가는 Error 가 발생하였다

해결법


1. 위와 같이 $? 의 값을 비교하여 앞선 명령의 결과코드가 0인지 확인하여, ok 를 선택할 때만 다음 단계로 넘어가게 구현했다
2. 이때, 받아온 Data 가 null 인지 비교하여 Data 를 입력했는지를 검사하였다

5. STACK 배포시 Image 를 찾지 못하는 문제

  • STACK 배포시 Image 를 찾지 못하는 문제는 간간히 발생한다. 이 이유는 사설 저장소에 접근하기 위한 인증 정보가 없기 때문이다

해결법

docker stack deploy -c /home/rapa/jdss/ymls/httpd_service.yml --with-registry-auth $1
  • 위와 같이 manager node 의 Harbor 및 Docker Hub 에 대한 인증 정보를 STACK 배포시 일시적으로 넘겨주어, 해당 node 에서 저장소에 접근이 가능하게 하여 해결하였다
profile
멋진 엔지니어가 될 때까지

0개의 댓글