Docker Compose : Flask, Redis, DynamoDB and Python

Docker Compose を使って環境構築を行う。

今回使うのは、Flask, Redis, DynamoDB, Python である。

Python で作成したコードを Flask で動かし、Redis をキャッシュとして利用し、DynamoDB にデータを永続化する。

導入環境

  • CentOS 7.7
  • Docker 19.03.7
  • Docker Compose 1.25.4

事前準備

PJディレクトリを作成する(任意のディレクトリで可)。

# mkdir docker-app

Flask のディレクトリを作成する。

# cd docker-app/
# mkdir flask

Flask

Dockerfile

Dockerfile を作成する。

# touch flask/Dockerfile

Dockerfile に下記を追加する。

FROM python:3.8-alpine

WORKDIR /code
ENV FLASK_APP app.py
ENV FLASK_RUN_HOST 0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY ./requirements.txt ./requirements.txt
RUN pip install -r requirements.txt
COPY ./app.py ./app.py
CMD ["flask", "run"]

requirements.txt

requirements.txt を作成する。

# touch flask/requirements.txt

requirements.txt に下記を追加する。

flask
redis
boto3

app.py

app.py を作成する。

# touch flask/app.py

app.py に下記を追加する。

import time
import datetime
import redis
import boto3
from flask import Flask

app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
cache_ttl = 5

db = boto3.resource(
    'dynamodb', 
    endpoint_url='http://dynamodb:8000', 
    region_name='localhost',
    aws_access_key_id='fakeId',
    aws_secret_access_key='fakeKey')

def get_hit_count_redis():
    retries = 5
    while True:
        try:
            hits:str = cache.get('hits')
            if not hits:
                hits = get_hit_count_dynamodb()

            new_value = int(hits) + 1

            # Update Redis
            pipe = cache.pipeline()
            pipe.set('hits', new_value)
            pipe.expire('hits', cache_ttl)
            pipe.execute()

            # Update DynamoDB
            table = db.Table('hits')
            response = table.put_item(
                Item={
                        'hits_id': '1',
                        'value': {'S': new_value}
                    }
            )

            return cache.get('hits')
        except redis.exceptions.ConnectionError as exc:
            if retries == 0:
                raise exc
            retries -= 1
            time.sleep(0.5)

def get_hit_count_dynamodb():
    ret_val = '0'
    retries = 5
    while True:
        table = db.Table('hits')
        try:
            response = table.get_item(
                Key={
                    'hits_id':'1'
                }
            )
            if ('Item' in response):
                ret_val = response['Item']['value']['S']

            return ret_val
        except botocore.exceptions.ClientError as ex:
            if retries == 0:
                raise ex
            retries -= 1
            time.sleep(0.5)

@app.route('/')
def hello():
    count = get_hit_count_redis()
    return 'Hello World! I have been seen {0} times. Access time is {1}.'.format(int(count), datetime.datetime.now())

docker-compose

docker-compose.yml を作成する。

# touch docker-compose.yml

docker-compose.yml

docker-compose.yml に下記を追記する。

version: '3'
services:
  flask:
    build: ./flask
    container_name: flask
    links:
     - "redis"
     - "dynamodb"
    ports:
      - "5000:5000"

  redis:
    image: redis:5.0-alpine
    container_name: redis
    expose:
     - 6379

  dynamodb:
    image: amazon/dynamodb-local:1.12.0
    command: -jar DynamoDBLocal.jar -inMemory -sharedDb
    container_name: dynamodb
    expose:
     - 8000
    ports:
      - "8000:8000"

コンテナ起動

コンテナを起動する。

# docker-compose up -d

AWS-CLI のインストール

DynamoDB を操作するために、AWS-CLI をインストールする。

# curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
# unzip awscliv2.zip
# ./aws/install

インストールを確認する。

# aws --version

f:id:saito_shion:20200310155107p:plain 初期設定を行う。

# aws configure

f:id:saito_shion:20200310170852p:plain

DynamoDB の設定

テーブルを作成する。

# aws dynamodb create-table \
   --table-name hits \
   --attribute-definitions AttributeName=hits_id,AttributeType=S \
   --key-schema AttributeName=hits_id,KeyType=HASH \
   --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1 \
   --endpoint-url http://localhost:8000

テーブルが作成されたことを確認する。

# aws dynamodb list-tables --endpoint-url http://localhost:8000

f:id:saito_shion:20200310172111p:plain

動作確認

ブラウザでhttp://localhost:5000/へアクセスし、アプリケーションが稼働しているかを確認する。 f:id:saito_shion:20200311154712p:plain

5秒以上経ったあとに、http://localhost:5000/へ再アクセスする。アクセスしたときに、数値がカウントアップされていることを確認する。 f:id:saito_shion:20200311154718p:plain

終わりに

Flask, Redis, DynamoDB, Python を連携して、簡単なアプリケーションを作成することができた。

注意する点としては、DynamoDB をインメモリデータベースとして稼働しているため、コンテナを削除するとデータも消える(インメモリデータベースとして起動しなければ永続化もできる)。

また、このプログラムのうち DynamoDB を呼び出す部分を削除すれば、Redis のみで5秒ごとに値がリセットされるアプリケーションにもできる。

参考サイト

https://github.com/aws-samples/aws-sam-java-rest

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-cliv2-linux.html

https://symfoware.blog.fc2.com/blog-entry-2208.html

https://michimani.net/post/aws-put-get-item-dynamodb-by-lambda-python/