From 5f3f5e22d1c600240ae1c661381dc6765481aea4 Mon Sep 17 00:00:00 2001 From: Maho Takara Date: Wed, 22 May 2024 07:46:11 +0900 Subject: [PATCH 1/3] Update test for build container --- .github/workflows/build.yaml | 32 ++++--- Dockerfile | 2 +- README.md | 88 ++++++++++--------- app.py | 162 +++++++++++++++++++++++++++++++---- compose.yaml | 39 +++++++++ 5 files changed, 247 insertions(+), 76 deletions(-) create mode 100644 compose.yaml 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..540066d 100644 --- a/README.md +++ b/README.md @@ -1,76 +1,74 @@ -# 3.5.1 Pythonで開発するREST-APIサーバー - ## イメージのビルドと実行 -``` -docker build -t ex1:1.5 . -docker run --name ex1 --publish 9100:9100 --detach ex1:1.5 -``` +docker build -t ex1:1.7 . +docker run --name ex1 --rm --publish 9107:9100 --detach ex1:1.7 + ## アクセス -``` -curl http://localhost:9100/ping;echo -``` +curl http://localhost:9107/ping;echo +curl http://localhost:9107/info;echo + ## コンテナへ入る -``` 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.7 ghcr.io/takara9/ex1:1.7 +docker push ghcr.io/takara9/ex1:1.7 + ## クリーンナップ -``` 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.7 +docker rmi ex1:1.7 + + +# テスト + + + +## DBのコンテナを起動 + +docker run -d --name mydb -p 3306:3306 \ +--env MARIADB_USER=user1 \ +--env MARIADB_PASSWORD=secret1 \ +--env MARIADB_DATABASE=mydb \ +--env MARIADB_ROOT_PASSWORD=secret0 \ +mariadb:latest + + +docker exec -it mydb bash +mariadb --user user1 --password=secret1 mydb + +## テーブルを作成 -## コードの更新方法 +CREATE TABLE Persons ( + `id` INT NOT NULL AUTO_INCREMENT, + `first_name` VARCHAR(50) NOT NULL, + `last_name` VARCHAR(50), + PRIMARY KEY (`id`), + UNIQUE INDEX `id_UNIQUE` (`id` ASC)); -``` -$ git clone git@github.com:takara9/ex1.git -$ git checkout -b add_api -$ git branch -# <コードの更新や追加> -$ git add . -$ git status -$ git commit -m "Add new api" -``` -CIが成功したら、add_apiブランチをmainブランチへマージする +## アクセステスト -## GitHubでのリリース方法 -メインブランチへ移動してコードを最新化する。そして、ブランチを削除 -``` -$ git checkout main -$ git pull -$ git branch -d update_branch -''' +mysql --host 127.0.0.1 --port 3306 --user user1 --password=secret1 mydb -リリースするTAGを設定する。 -ここで付与するTAGはコンテナイメージのタグになるので、リポジトリを確認して、タグ名を決めること。 -``` -TAG=1.5 -$ git tag -a $TAG -m "version $TAG" -$ git push origin $TAG -``` +curl -X POST -H "Content-Type: application/json" -d '{"fname" : "maihei" , "lname" : "isono"}' http://localhost:9107/person/ +{"fname":"maihei","lname":"isono"} -コンテナのイメージを、タグを選定してリリースする。 +curl -X GET -H "Content-Type: application/json" http://localhost:9107/persons \ No newline at end of file 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 From a6239c711a8ac75432b68aaaad7469dc23f0c310 Mon Sep 17 00:00:00 2001 From: Maho Takara Date: Wed, 22 May 2024 08:18:46 +0900 Subject: [PATCH 2/3] update README --- README.md | 88 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 540066d..d6fcd7c 100644 --- a/README.md +++ b/README.md @@ -1,74 +1,76 @@ -## イメージのビルドと実行 +# 3.5.1 Pythonで開発するREST-APIサーバー -docker build -t ex1:1.7 . -docker run --name ex1 --rm --publish 9107:9100 --detach ex1:1.7 +## イメージのビルドと実行 +``` +docker build -t ex1:1.6 . +docker run --name ex1 --publish 9100:9100 --detach ex1:1.6 +``` ## アクセス -curl http://localhost:9107/ping;echo -curl http://localhost:9107/info;echo - +``` +curl http://localhost:9100/ping;echo +``` ## コンテナへ入る +``` 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.7 ghcr.io/takara9/ex1:1.7 -docker push ghcr.io/takara9/ex1:1.7 - +docker tag ex1:1.6 ghcr.io/takara9/ex1:1.6 +docker push ghcr.io/takara9/ex1:1.6 +``` ## クリーンナップ +``` docker stop ex1 docker rm ex1 -docker rmi ghcr.io/takara9/ex1:1.7 -docker rmi ex1:1.7 - - -# テスト - - - -## DBのコンテナを起動 - -docker run -d --name mydb -p 3306:3306 \ ---env MARIADB_USER=user1 \ ---env MARIADB_PASSWORD=secret1 \ ---env MARIADB_DATABASE=mydb \ ---env MARIADB_ROOT_PASSWORD=secret0 \ -mariadb:latest - - -docker exec -it mydb bash -mariadb --user user1 --password=secret1 mydb - +docker rmi ghcr.io/takara9/ex1:1.6 +docker rmi ex1:1.6 +``` -## テーブルを作成 -CREATE TABLE Persons ( - `id` INT NOT NULL AUTO_INCREMENT, - `first_name` VARCHAR(50) NOT NULL, - `last_name` VARCHAR(50), - PRIMARY KEY (`id`), - UNIQUE INDEX `id_UNIQUE` (`id` ASC)); +## コードの更新方法 +``` +$ git clone git@github.com:takara9/ex1.git +$ git checkout -b add_api +$ git branch +# <コードの更新や追加> +$ git add . +$ git status +$ git commit -m "Add new api" +``` +CIが成功したら、add_apiブランチをmainブランチへマージする -## アクセステスト +## GitHubでのリリース方法 +メインブランチへ移動してコードを最新化する。そして、ブランチを削除 -mysql --host 127.0.0.1 --port 3306 --user user1 --password=secret1 mydb +``` +$ git checkout main +$ git pull +$ git branch -d update_branch +''' +リリースするTAGを設定する。 +ここで付与するTAGはコンテナイメージのタグになるので、リポジトリを確認して、タグ名を決めること。 -curl -X POST -H "Content-Type: application/json" -d '{"fname" : "maihei" , "lname" : "isono"}' http://localhost:9107/person/ -{"fname":"maihei","lname":"isono"} +``` +TAG=1.6 +$ git tag -a $TAG -m "version $TAG" +$ git push origin $TAG +``` -curl -X GET -H "Content-Type: application/json" http://localhost:9107/persons \ No newline at end of file +コンテナのイメージを、タグを選定してリリースする。 From 7346cac990cc5ebe4d5fe1309e52c5d5036d44ad Mon Sep 17 00:00:00 2001 From: Maho Takara Date: Wed, 22 May 2024 08:22:57 +0900 Subject: [PATCH 3/3] fix typo README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d6fcd7c..72d2151 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,8 @@ CIが成功したら、add_apiブランチをmainブランチへマージする $ git checkout main $ git pull $ git branch -d update_branch -''' +``` + リリースするTAGを設定する。 ここで付与するTAGはコンテナイメージのタグになるので、リポジトリを確認して、タグ名を決めること。