diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 87c12f5..085862f 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -35,11 +35,11 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + #- name: Extract metadata (tags, labels) for Docker + # id: meta + # uses: docker/metadata-action@v5 + # with: + # images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - name: Build a image id: push @@ -47,21 +47,31 @@ jobs: with: context: . push: false - tags: ${{ steps.meta.outputs.tags }} + #tags: ${{ steps.meta.outputs.tags }} + tags: ex1:test #platforms: linux/amd64,linux/arm64 - labels: ${{ steps.meta.outputs.labels }} + #labels: ${{ steps.meta.outputs.labels }} + labels: test - name: Start a container from the image run: | docker images - docker run -d --name test -p 9100:9100 ${{ steps.meta.outputs.tags }} - docker ps + # docker run -d --name test -p 9100:9100 ${{ steps.meta.outputs.tags }} + docker compose up -d + docker compose ps - name: Test the container run: | - sleep 5 - docker ps + sleep 10 + docker compose ps -a curl --silent --retry 3 --include http://127.0.0.1:9100/ping | grep "200 OK" [ $? -ne 0 ] && (echo "error"; exit 1) + curl --silent --retry 3 --include http://127.0.0.1:9100/info | grep "200 OK" + [ $? -ne 0 ] && (echo "error"; exit 1) + curl --silent --retry 3 --include http://127.0.0.1:9100/healthz | grep "500 INTERNAL SERVER ERROR" + [ $? -ne 0 ] && (echo "error"; exit 1) + curl --silent --retry 3 --include http://127.0.0.1:9100/readiness | grep "200 OK" + [ $? -ne 0 ] && (echo "error"; exit 1) + exit 0 diff --git a/Dockerfile b/Dockerfile index dab8c25..0191484 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM ubuntu:22.04 # 依存するモジュールをインストール RUN apt-get update && apt-get install -y python3 python3-pip -RUN pip install flask +RUN pip3 install flask mysql-connector-python # アプリケーションのインストール RUN mkdir /app diff --git a/README.md b/README.md index 75b5af0..72d2151 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ ## イメージのビルドと実行 ``` -docker build -t ex1:1.5 . -docker run --name ex1 --publish 9100:9100 --detach ex1:1.5 +docker build -t ex1:1.6 . +docker run --name ex1 --publish 9100:9100 --detach ex1:1.6 ``` ## アクセス @@ -25,8 +25,8 @@ docker exec -it ex1 bash export CR_PAT=YOUR_TOKEN export USERNAME=YOUR USERID echo $CR_PAT | docker login ghcr.io -u $USERNAME --password-stdin -docker tag ex1:1.4 ghcr.io/takara9/ex1:1.5 -docker push ghcr.io/takara9/ex1:1.5 +docker tag ex1:1.6 ghcr.io/takara9/ex1:1.6 +docker push ghcr.io/takara9/ex1:1.6 ``` ## クリーンナップ @@ -34,8 +34,8 @@ docker push ghcr.io/takara9/ex1:1.5 ``` docker stop ex1 docker rm ex1 -docker rmi ghcr.io/takara9/ex1:1.5 -docker rmi ex1:1.5 +docker rmi ghcr.io/takara9/ex1:1.6 +docker rmi ex1:1.6 ``` @@ -62,13 +62,14 @@ CIが成功したら、add_apiブランチをmainブランチへマージする $ git checkout main $ git pull $ git branch -d update_branch -''' +``` + リリースするTAGを設定する。 ここで付与するTAGはコンテナイメージのタグになるので、リポジトリを確認して、タグ名を決めること。 ``` -TAG=1.5 +TAG=1.6 $ git tag -a $TAG -m "version $TAG" $ git push origin $TAG ``` diff --git a/app.py b/app.py index b3a9a91..f96c357 100644 --- a/app.py +++ b/app.py @@ -1,42 +1,166 @@ +import os import signal import sys import time -from flask import Flask, request +import json +import logging from socket import gethostname, gethostbyname +from flask import Flask, request, jsonify, make_response +import mysql.connector -# ログ保存 -def logger(msg): - f = open('/app/app.log', 'a') - f.write(msg) - f.close() +# 環境変数の取り込み関数 +def loadenv(envvar, default): + w = os.environ.get(envvar) + if w is None: + w = default + return w + +# 環境変数の取り込みとDB接続 +def db_connect(): + try: + ret = mysql.connector.connect( + host=db_host, + port=db_port, + database=db_database, + user=db_user, + password=db_user_passwd + ) + return ret + except mysql.connector.Error as err: + return None + +def db_connect_readonly(): + try: + ret = mysql.connector.connect( + host=db_readonly_host, + port=db_port, + database=db_database, + user=db_user, + password=db_user_passwd + ) + return ret + except mysql.connector.Error as err: + print(err) + sys.exit() + return None # シグナルを受けた時の処理 def handler(signum, frame): # ここにアプリケーションの終了処理を書く - logger("Accept SIGNAL\n") - logger("\n") - time.sleep(5) - # コンテナ終了 - sys.exit() + ## KubernetesからSIGTERMが来ると、それ以降はリクエストが転送されない。 + logging.debug("Accept SIGNAL\n") + # ここでコンテナ終了しない事で、終了間際の応答を返す + ## sys.exit() + +## +## MAIN +## +### 環境変数 +db_database = loadenv('MARIADB_DATABASE','mydb') +db_root_passwd = loadenv('MARIADB_ROOT_PASSWORD','secret0') +db_host = loadenv('MARIADB_HOST','mariadb') +db_readonly_host = loadenv('MARIADB_READONLY_HOST','mariadb') +db_port = loadenv('MARIADB_PORT','3306') +db_user = loadenv('MARIADB_USER','user1') +db_user_passwd = loadenv('MARIADB_PASSWORD','secret1') +### ロギング +logging.basicConfig(level=logging.DEBUG, format='%(message)s') +logging.debug('Start Web Server') +### シグナル +signal.signal(signal.SIGTERM, handler) # シグナル受信時の処理先を定義 +### Webサービス +app = Flask(__name__) # Webサービス +cnx = db_connect() # データベース接続 +cnro = db_connect_readonly() # 読み取り専用データベース接続 -# シグナルSIGTERMを受けた時の処理先関数を定義 -signal.signal(signal.SIGTERM, handler) +if __name__ == "__main__": + app.run(debug=True) -# Webサービス -app = Flask(__name__) -logger("Start Web service\n") # ping応答 @app.route("/ping") def ws_ping(): return "PONG!" -# ホスト情報 +# ホスト情報 @app.route("/info") def ws_info(): hostname = gethostname() resp = "" resp = resp + 'Host Name: %s' % hostname + "\n" resp = resp + 'Host IP: %s' % gethostbyname(hostname) + "\n" - resp = resp + 'Client IP : %s' % request.remote_addr + "\n" - return resp + return resp + 'Client IP : %s' % request.remote_addr + "\n" + + +# レディネスプローブ +@app.route('/readiness', methods=['GET']) +def rediness(): + try: + cnxx = mysql.connector.connect( + host=db_host, + port=db_port, + database="mysql", + user="root", + password=db_root_passwd + ) + cursor = cnxx.cursor() + cursor.execute("SELECT * FROM user") + cnxx.close() + return jsonify({}), 200 + except mysql.connector.Error as err: + logging.debug('err:', err) + return jsonify({}), 500 + +# ライブネスプローブ +@app.route('/healthz', methods=['GET']) +def healthz(): + try: + cnxx = mysql.connector.connect( + host=db_host, + port=db_port, + database=db_database, + user=db_user, + password=db_user_passwd + ) + cursor = cnxx.cursor() + cursor.execute("SELECT id FROM Persons") + cnxx.close() + return jsonify({}), 200 + except mysql.connector.Error as err: + logging.debug('err:', err) + return jsonify({}), 500 + + +## コントローラー +# 登録 データの返し方を再考慮 +@app.route('/person/', methods=['POST']) +def recPerson(): + reqData = json.dumps(request.json) + personData = json.loads(reqData) + sql = 'INSERT INTO Persons (first_name, last_name) VALUES ("%s", "%s")' % (personData['fname'], personData['lname']) + cur = cnx.cursor(buffered=True) + cur.execute(sql) + cnx.commit() + return request.json, 200 + +# IDでユーザー情報取得 +@app.route('/person//', methods=['GET']) +def getPerson(id): + cur = cnx.cursor(buffered=True) + sql = 'SELECT id, first_name, last_name FROM Persons WHERE id = %s' % id + cur.execute(sql) + for (did, first_name, last_name) in cur: + return jsonify({"id": did, "first_name": first_name, "last_name": last_name}), 200 + +# 全ユーザー情報取得 +@app.route('/persons', methods=['GET']) +def getPersons(): + cur = cnro.cursor(buffered=True) + sql = 'SELECT id, first_name, last_name FROM Persons' + cur.execute(sql) + result = [] + for (id, first_name, last_name) in cur: + result.append({"id": id, "first_name": first_name, "last_name": last_name}) + return jsonify(result), 200 + + diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..afd00e6 --- /dev/null +++ b/compose.yaml @@ -0,0 +1,39 @@ +version: '3.1' + +networks: + my-net: + driver: bridge + +volumes: + db: + driver: local + +services: + ex1: + image: ex1:test + restart: always + ports: + - 9100:9100 + environment: + MARIADB_DATABASE: mydb + MARIADB_ROOT_PASSWORD: secret0 + MARIADB_HOST: mariadb + MARIADB_READONLY_HOST: mariadb + MARIADB_PORT: 3306 + MARIADB_USER: user1 + MARIADB_PASSWORD: secret1 + networks: + - my-net + + mariadb: + image: mariadb:latest + restart: always + environment: + MARIADB_DATABASE: mydb + MARIADB_USER: user1 + MARIADB_PASSWORD: secret1 + MARIADB_ROOT_PASSWORD: secret0 + volumes: + - db:/var/lib/mysql + networks: + - my-net