본문 바로가기
프로젝트

도커 컨테이너 구성 및 활용(2)

by 엑츄얼리 2021. 8. 4.

Flask로 Web App을 개발을 하고 데이터베이스(MariaDB)와 연동을 하는 방법을 알아본다. CURL을 사용 하여 기본적인 REST API(HTTP methods: GET, POST, DELETE)를 테스트 해본다.

* test-net

=> Docker Container는 격리된 환경에서 실행되기 때문에 다른 컨테이너와 통신이 불가능

     이 때, network를 통해 여러개의 컨테이너를 연결시켜 통신이 가능하게 할 수 있음

1) MariaDB image를 생성 (내부데이터 有)

FROM mariadb:latest
# mariadb:latest를 기반 이미지로 이미지 생성

ENV MYSQL_ROOT_PASSWORD=189756
# DB의 비밀번호 설정

ENV MYSQL_DATABASE=alswkdrb
# DB의 이름 설정

COPY *.sql /docker-entrypoint-initdb.d/
# 디렉토리의 모든 .sql파일을 docker-entrypoint-initdb.d 파일에 복사

* Docker image가 실행 시에 docker-entrypoint-initdb.d에 있는 sql 스크립트 파일을 읽어 데이터베이스에 저장

CREATE TABLE IF NOT EXISTS `cloud_user` (  
    `user_id` bigint NOT NULL AUTO_INCREMENT,   
    `user_name` varchar(45) DEFAULT NULL,   
    `user_email` varchar(45) DEFAULT NULL,   
    `user_bio` varchar(255) DEFAULT NULL,   
    PRIMARY KEY (`user_id`) 
    ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ;

INSERT INTO `cloud_user` (
    `user_id`,`user_name`,`user_email`, `user_bio`) 
    values  
    (1,'jk M','alswkdrb1@gmail.com', 'student');

* NOT NULL : 공백 비허용

  DEFAULT NULL : 공백 허용

  AUTO_INCREMENT=2 : 2부터 1씩 증가하는 값

 

$ docker build -t alswkdrb1/box1:mariadb_v2 .

=> mariadb image 생성

 

2) Mariadb container 생성

$ docker run -p 3306:3306 --net test-net --name my-mariadb -d alswkdrb1/box1:mariadb_v2

=> 직전에 생성한 image를 포트 = 외부 3306 : 내부 3306, network = test-net, 이름 = my-mariadb 로

     detach모드로 실행

 

3) Flask 이미지 만들기 + Flask Container와 Mariadb container 연동하여 DB읽고 쓰기

3-1) main.py

#main.py

# third-party imports
import pymysql
from flask import jsonify, render_template, request, redirect

# local imports
from app import app
from models import Results
from db_config import mysql

# route
@app.route('/')
def index_page():
    return render_template('index.html')

@app.route('/user', methods=['GET'])
def users():
	conn = None
	cursor = None
	try:
		conn = mysql.connect()
		cursor = conn.cursor(pymysql.cursors.DictCursor)
		cursor.execute("SELECT * FROM cloud_user")
		rows = cursor.fetchall()
		res = jsonify(rows)
		res.state_code = 200
		return res
		# table = Results(rows)
		# table.border = True
		# return render_template('users.html', table=table)
	except Exception as e:
		print(e)
	finally:
		cursor.close()
		conn.close()

@app.route('/add', methods=['POST'])
def add_user():
	conn = None
	cursor = None
	try:
		if request.is_json:
			req = request.get_json()

			_name = req['name']
			_email = req['email']
			_bio = req['bio']
		
		if _name and _email and request.method == 'POST':
			sql = "INSERT INTO cloud_user(user_name, user_email, user_bio) VALUES(%s, %s, %s)"
			data = (_name, _email, _bio,)
			conn = mysql.connect()
			cursor = conn.cursor()
			cursor.execute(sql, data)
			conn.commit()
			return redirect('/user')
		else:
			return 'Error while adding user'
	except Exception as e:
		print(e)
	finally:
		cursor.close() 
		conn.close()

@app.route('/delete/<int:id>', methods=['DELETE'])
def delete_user(id):
	conn = None
	cursor = None
	try:
		conn = mysql.connect()
		cursor = conn.cursor()
		cursor.execute("DELETE FROM cloud_user WHERE user_id=%s", (id,))
		conn.commit()
		return redirect('/user')
	except Exception as e:
		print(e)
	finally:
		cursor.close() 
		conn.close()

@app.errorhandler(404)
def not_found(error=None):
	message = {
        'status': 404,
        'message': 'Not Found: ' + request.url,
    }
	res = jsonify(message)
	res.state_code = 404
    
	return res
	
if __name__ == "__main__":
    app.run(debug=True, host='0.0.0.0')

3-2) models.py

from flask_table import Table, Col
 
class Results(Table):
    user_id = Col('Id')
    user_name = Col('Name')
    user_email = Col('Email')
    user_bio = Col('Bio')

3-3) db_config.py

from app import app
from flaskext.mysql import MySQL
import os

mysql = MySQL()
 
# MySQL configurations
app.config['MYSQL_DATABASE_USER'] = os.environ['DB_USER']
app.config['MYSQL_DATABASE_PASSWORD'] = os.environ['DB_PASSWORD']
app.config['MYSQL_DATABASE_DB'] = os.environ['DB_NAME'] 
app.config['MYSQL_DATABASE_HOST'] = os.environ['DB_HOST'] 

mysql.init_app(app)

3-4) app.py

from flask import Flask

app = Flask(__name__)
app.secret_key = "secretkey"

3-5) requirements.txt

flask
pymysql
flask_table
flask-mysql

3-6) Dockerfile

FROM python:3.9.5-alpine
WORKDIR /app
ADD . /app
RUN pip install -r requirements.txt
CMD ["python", "main.py"]

$ docker build -t alswkdrb1/box1:cloudflask_v1 .

=> flask 이미지 생성

 

$ docker run -p 5000:5000 --net test-net --env-file ./env.list alswkdrb1/box1:cloudflask_v1

=> 이전에 만든 flask이미지로 환경파일(env.list)을 읽어들이며 실행

# env.list

DB_USER=root
DB_PASSWORD=189756
DB_NAME=alswkdrb
DB_HOST=my-mariadb

cloudflask_v1이미지를 컨테이너로 실행
정상적으로 db를 읽어옴
Post
Delete

4) Docker Compose

Docker Compose를 활용하면 여러개의 컨테이너를 손쉽게 구성하고 관리할 수 있다.

 

docker-compose.yml

version: "2"
services:
  my-mariadb:
    image: alswkdrb1/box1:mariadb_v2
    ports:
      - "3306:3306" 
  my-flask-app:
    links: 
      - my-mariadb
    image: alswkdrb1/box1:cloudflask_v2
    ports:
      - "5000:5000"
    environment:
      - DB_USER=root
      - DB_PASSWORD=189756
      - DB_NAME=alswkdrb
      - DB_HOST=my-mariadb

$ docker-compose up -d

docker compose 실행 후 DB확인 및 변경

$ docker-compose down

댓글