Run The Bridge
python/Flask와 DB를 이용한 Docker-compose.yml 본문
학교에서 하는 Docker 교육 Toyproject을 받았다.
익숙한 언어인 python과 웹을 띄우기 위한 Flask, 데이터를 담기위한 DB를 이용하여 아래의 아키텍처를 완성해야 한다.
0. Dockerfile을 이용하여 DB 먼저 구축하기
나는 DB를 'Mariadb:10.6.3ver'을 사용하였다.
Dockerfile의 내용은 다음과같다.
# vim Dcokerfile_mariaDB_01
FROM mariadb:10.6.3 # mariadb 버전선택
ENV MYSQL_ROOT_PASSWORD=root # root pw 설정
ENV MYSQL_DATABASE=flask01_db # 생성할 DB 이름 설정
ENV MYSQL_USER=flask01 # user 생성
ENV MYSQL_PASSWORD=flask01 # user pw 생성
COPY my.cnf /etc/mysql/my.cnf # my.cnf의 설정내용 복사
EXPOSE 3000 # port 3000번으로 설정
CMD ["mysqld"] # 명령어 mysqld 사용
2대를 구축해야했기 때문에 첫번째 DB의 이름은 Dcokerfile_mariaDB_01로 설정하였다.
두번째 DB Dockerfile은 다음과 같다.
# vim Dockerfile_mariadb_02
FROM mariadb:10.6.3
ENV MYSQL_ROOT_PASSWORD=root
ENV MYSQL_DATABASE=flask02_db
ENV MYSQL_USER=flask02
ENV MYSQL_PASSWORD=flask02
COPY my.cnf /etc/mysql/my.cnf
EXPOSE 3000
CMD ["mysqld"]
Dockerfile을 build 시켜준다.
docker build -t mariadb01:0.0 -f Dockerfile_mariaDB_01 .
docker build -t mariadb02:0.0 -f Dockerfile_mariaDB_02 .
여기서 Dockerfile을 이용하여 build을 해서 test를 많이하는데, 처음부터 Docker-compose.yml 를 만들어서 했으면 매우 수월하게 할 수 있었는데 몰랐다...
2개의 image가 잘 생성되었다.
이제 run을 시켜주면 된다.
docker run -d -p 3000:3000 --volume /var/lib/mysql --network project_network --name mariadb01 mariadb01:0.0
docker run -d -p 3000:3000 --volume /var/lib/mysql --network project_network --name mariadb02 mariadb02:0.0
여기서 --volume 과 --network를 써주었는데, 같은 network안에 존재해야 통신이 되기 때문이고, volume은 DB를 껏다켜도 데이터가 날라가지 않게하기 위해 설정해준다. volume 위치는 my.cnf에 기술해져있다.
datadir = /var/lib/mysql
docker ps -a
docker exec -it [CONTAINER ID] bash
databases와 user접속이 잘 된다.
1. Dockerfile을 이용하여 python 구축하기
python Dockerfile의 내용은 다음과같다.
# vim Dockerfile_python_01
FROM python:3 # python ver은 3
WORKDIR /usr/src/app # /usr/src/app으로 이동
COPY requirements.txt . # requirements.txt 복사
RUN pip install --no-cache-dir -r requirements.txt # requirements.txt 내용 실행
RUN pip install pymysql # mysql 연동을 위한 pymysql 설치
COPY . . # 현재 디렉토리에 있는거 전부 복사
EXPOSE 8000 # 포트 8000번 open
CMD ["python", "./app.py"] # python app.py 실행
python Dockerfile 2번의 내용은 다음과같다.
# vim Dockerfile_python_02
FROM python:3
WORKDIR /usr/src/app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install pymysql
COPY . .
EXPOSE 8000
CMD ["python", "./app2.py"]
requirements.txt 내용은 다음과같다
# vim requirements.txt
flask==2.0.1
pymysql
requests==2.25.1
urllib3==1.26.4
xmltodict==0.12.0
app.py의 내용은 다음과 같다.
# vim app.py
import pymysql
import time
from flask import Flask
time.sleep(5)
app = Flask(__name__)
@app.route("/select", methods=["GET"])
def select():
juso_db = pymysql.connect(
user='flask01',
password='flask01',
host='mariadb01',
port=3000,
db='flask01_db',
charset='utf8'
)
cursor = juso_db.cursor()
sql = "select id, email, phone_number from private;"
cursor.execute(sql)
row = cursor.fetchall()
print(row)
lst = []
for data in row:
dic = {
'id' : data[0],
'email' : data[1],
'phone_number' : data[2]
}
lst.append(dic)
juso_db.close()
return str(lst)
@app.route('/')
def hello_world():
return 'Hello, world!'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
DB처럼 똑같이 build, run 시켜주면 된다.
docker build -t flask01:0.0 -f Dockerfile_python_01 .
docker build -t flask02:0.0 -f Dockerfile_python_02.
port는 내부포트는 8000, 외부 접속포트는 8081, 8082로 정의되어 있다.
docker run -d -p 8081:8000 --network project_network --name flask01 flask01:0.0
docker run -d -p 8082:8000 --network project_network --name flask02 flask02:0.0
docker logs 명령을 이용하여 app.py가 실행되었는지, 오류가 났는지 확인이 가능하다.
http:192.168.100.150:8081 로 들어가면 Hello world를 볼 수 있다.!
app.py에 /select page를 호출하면 DB의 내용이 나오는데, DB image를 생성하고, run 한 후에 안에 table를 생성하고
data를 insert 시켜주어야 나온다.
다음과 같이 data를 넣어주고 확인해본다.
docker flask01번을 rebuild 시켜주고, rerun 시켜준다. 그 후 /select page를 호출한다.
연동이 잘 된것을 확인할 수 있다.
2. Dockerfile을 이용하여 python main구축하기
이제 flask와 DB간의 연동은 되었으므로, API를 사용할 main flask server를 구축해야 한다.
Dockerfile_main의 내용은 다음과 같다.
# vi Dockerfile_main
FROM python:3
WORKDIR /usr/src/app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install pymysql
COPY . .
EXPOSE 8000
CMD ["python", "./app_main.py"]
그게 차이는 없다. 어차피 py에서 내용을 다뤄주기 때문이다.
app_main.py의 내용은 다음과 같다.
# vim app_main.py
import pymysql
import time
import requests
from flask import Flask
import json
time.sleep(5)
app = Flask(__name__)
@app.route('/result', methods=["GET"])
def hello():
res1 = requests.get('http://flask01:8000/select')
# res2 = requests.get('http://flask02:8000')
# //res1, res2의 결과를 가공
# //...
return str(res1.text)
@app.route('/')
def hello_world():
return 'Hello, world!'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
똑같이 build & run을 시켜준다.
docker build -t main:0.0 -f Dockerfile_main .
docker run -d -p 80:8000 --network project_network --name main main:0.0
마찬가지로 docker logs를 이용하여 main page에 접속한다.
result page를 호출해서 매우 잘 불러온다. 성공!
모든 dockerfile이 잘 동작하므로 이제 docker-compose.yml 파일을 만들어야 한다.
3. Docker-compose.yml 파일 작성하기
docker-compose.yml 파일의 내용은 다음과 같다.
# vim docker-compose.yml
version: '3.0' # version 정의
services: # service 아래단에 정의
main: # main에 관련
build:
context: .
dockerfile: ./Dockerfile_main # build 시킬 dockerfile
image: main:0.0 # 사용자 지정 image 이름
ports:
- "80:8000" # open port 설정
networks:
- project_network # network 설정
flask01: # flask01에 관련
build:
context: .
dockerfile: ./Dockerfile_python_01 # build 시킬 dockerfile
image: flask01:0.0 # 사용자 지정 image 이름
ports:
- "8081:8000" # open port 설정
networks:
- project_network # network 설정
flask02:
build:
context: .
dockerfile: ./Dockerfile_python_02
image: flask02:0.0
ports:
- "8082:8000"
networks:
- project_network
mariadb01: # mariadb01에 관련
build:
context: .
dockerfile: ./Dockerfile_mariaDB_01 # build할 dockerfile 지정
image: mariadb01:0.0 # 사용자 지정 image 이름
volumes:
- mariadb:/var/lib/mysql # volume 설정, my.cnf에 정의
networks:
- project_network # network 설정
mariadb02:
build:
context: .
dockerfile: ./Dockerfile_mariaDB_02
image: mariadb02:0.0
volumes:
- mariadb2:/var/lib/mysql
networks:
- project_network
volumes: # volume 정의
mariadb:
external: true # 기존의 볼륨을 사용하도록 설정
mariadb2:
external: true
networks:
project_network:
external: true # 기존의 네트워크를 사용하도록 설정
docker-compose.yml 파일을 만들 때, 하나씩해보면서 test해보았다.
mariadb01 설정 후 테스트, mariadb02 설정 후 테스트 이런 식으로 했다.
이제 dockerfile로 생 run 중인 process들을 모두 down시키고 compose만으로 rebuild 해보자
docker-compose up --build -d
데이터가 volume을 이용하여 매우 잘 들어가있으며, 호출이 매우 잘 되었다. 성공! 이제 swarm 형태로 배포시켜야 한다.
4. Docker stack으로 service 올리기
우선은 올라가있는 docker-compose를 내려줘야 한다.
docker-compose down
그리고 다음과같은 오류가 뜰 수 있다.
network "project_network" is declared as external, but it is not in the right scope: "local" instead of "swarm"
그러면 docker-compose.yml 에서 network 부분에 external: true를 지워준다 그후에 다음 명령 실행
docker stack deploy -c docker-compose.yml myproject
docker stack ls
docker stack ps myproject
5개가 모두 running으로 나오지만, 실행장소가 swarm-manger로 잡혀있다.
나머지 node에서는 image가 없다고나온다.
다른 node에서도 올라올 수 있도록 해결해야 한다.
사설 registry를 만들어서 이미지를 저장해야 한다.
docker run -d --name myregistry -p 5000:5000 --restart=always registry:2.6
2장에서 배운 daemon.json 파일을 수정해야 한다.
vi /etc/docker/daemon.json
뒷부분에 'myregistry.kpc.or.kr:5000'을 추가해준다.
그 후 docker restart
systemctl restart docker
다음에 각 node마다 /etc/hosts 파일에 다음을 추가한다.
192.168.100.150 myregistry.kpc.or.kr
python image 3개를 registry에 push를 해두면 다른 node에서 pull를 할 수 있다.
먼저 각 python의 NAME과 TAG를 변경시켜준다.
root@swarm-manager ~/project # docker tag flask01:0.0 myregistry.kpc.or.kr:5000/flask01:0.0
root@swarm-manager ~/project # docker tag flask02:0.0 myregistry.kpc.or.kr:5000/flask02:0.0
root@swarm-manager ~/project # docker tag main:0.0 myregistry.kpc.or.kr:5000/main:0.0
docker-compose.yml 파일에서 image를 바꿔주어야 한다.
이름만 바꾸었다고 worker node가 접속할 수 없다.
registry server에 저장시켜야한다 --> push
docker push myregistry.kpc.or.kr:5000/flask01:0.0
docker push myregistry.kpc.or.kr:5000/flask02:0.0
docker push myregistry.kpc.or.kr:5000/main:0.0
이제 확인을 위해서 docker stack에 올라간 것을 내려준다.
docker stack ls
docker stack rm myproject
다시 docker stack을 올려준다.
docker stack deploy -c docker-compose.yml myproject
이러면 각 node에서 올라오는 것을 볼 수 있다.
'Cloud > docker' 카테고리의 다른 글
docker 6일차 (0) | 2021.07.27 |
---|---|
config을 사용해서 mysql port 변경하기 (0) | 2021.07.26 |
docker 5일차 (0) | 2021.07.23 |
dockerfile을 이용하여 DB와 python 연동하기 (0) | 2021.07.23 |
docker 4일차 (0) | 2021.07.22 |