Web

GCPでのWebサービスの作り方(Python、Flask、MYSQL、Mail、Apache) 2/2

投稿日:2021年9月18日 更新日:

以下からの続きとなります。
GCPでのWebサービスの作り方(Python、Flask、MYSQL、Mail、Apache) 1/2 – DXインテリジェンス (itresourcetech.net)

■  ステップ4)GCPにWebアプリケーション環境をセットアップ

①Ubuntuにログイン

GCE(Ubuntu)のVMインスタンスを選択し、SSHでログインをします。(VMインスタンスを開始しておくこと)SSHプルダウンをから「ブラウザウィンドウで開く」を選択します。

ブラウザ上でターミナルが開きます。

※rootでがログインが必要な場合には、以下で、パスワードを設定してください。

sudo passwd root

②各種パッケージのインストール

・Anacondaのインストール

Python、Flaskの各種パッケージを個別にインストールすることもできますが、ここは一式入っているAnacondaをまずはインストールします。

今回は、以下から Anaconda 3のLinux用インストーラを、いったん自分のPCにダウンロードしてインストールしました。
https://www.anaconda.com/products/individual#Downloads

ダウンロードした「Anaconda3-2021.05-Linux-x86_64.sh」をSSHの設定→アップロード機能を使ってUbuntuに送ります。(ログインユーザのカレントに保存されます)

あとは、ターミナルからインストーラーを実行し、インストールします。

・MySQL接続モジュールのインストール

PythonからMySQLと接続するためのモジュールをインストールします。
以下をターミナルから実行します。

 sudo ./pip3 install mysql-connector-python


 ※ 類似のものに「mysql-connector」がありますが、 varcharがすべてbytearrayで返却されるので使えません。


・Apacheのインストール

Apacheをインストールします。
以下をターミナルから実行します。

 パッケージの更新

  sudo apt-get update

 Apache2のインストール

  sudo apt-get install apache2
  sudo apt install apache2-dev

・ Apache連結用モジュールのインストール

FlaskとApacheを連結するために必要なWSGIモジュールをインストールします。
以下をターミナルから実行します。

  sudo ./pip3 install mod_wsgi

インストール後、以下を実行します。

 ~/.local/bin/mod_wsgi-express install-module

そうすると以下のような文字列が返却されます。あとで使うので、記録しておきます。

 LoadModule wsgi_module “/usr/lib/apache2/modules/mod_wsgi-py38.cpython-38-x86_64-linux-gnu.so”
 WSGIPythonHome “/home/ホームディレクトリ/anaconda3”



③MySQLにユーザとデータベースを作成

Webアプリケーションからアクセスするためのユーザを登録しておきます。
GCPのダッシュボートからSQL画面を開き、インスタンスを選択し、ユーザの追加を実施します。
たとえば、user001を新規に追加し、パスワードを設定します。

次に、Webアプリケーションで使うデータベースを作成します。
そのために、SSHのターミナルからmysqlのクライアントツールを使います。
そして、 mysqlのクライアントツール を使うためだけに、 SSHのターミナルから 以下を実行し、GCEのUbuntuにMYSQL80をインストールします。

 sudo apt-get install mysql-community-server


MySQLのクライアントツールで、MySQLのインスタンスに接続するには、IPアドレスを知っておく必要があります。
GCPのダッシュボートからSQL画面を開き、インスタンスを選択すると、プライベートIPアドレスがそれに当たります。


SQL言語で書かれたスクリプトをテキストファイルで作成し、GCEのUbuntuにアップロードします。
例えば、以下のようなデータベースの作成、テーブルの作成のスクリプトです。

[SQL.TXT]

# データベース作成
CREATE DATABASE TestDB;

# QAテーブル作成
create table TestDB.QA_Tbl(	
	id		int unsigned not null primary key  auto_increment,	#QA ID
	dt		datetime,						#日時
	name 		varchar(256),						#お名前
	email 		varchar(256),						#メールアドレス
	comment		varchar(2048)						#内容
	);

SSHのターミナルから以下を実行後、パスワードを入力し、 MySQLのクライアントツールを起動します。

 mysql -h 10.74.128.3 -u user001 -p


MySQLのクライアントツールのプロンプトから上記のスクリプトを実行します。

 mysql> source <スクリプトファイルの絶対パス>


その結果、データベースとテーブルがMySQLのインスタンス内に作成されます。
確認のため、 MySQLのクライアントツール のプロンプトから以下のSQL文を入力します。
(作成されたデータベース名が表示されます)

 mysql> show databases;


④ Python+Flask のWebアプリケーションのセットアップ

Webアプリケーションは、自分のPCで開発した後、GCEのUbuntu上にアップロードします。
今回は、ブラウザから質疑(QA)を受け取り、MySQLへのデータベースに登録し、回答者へメール送信するテストプログラムを作成します。

メインとなるソースコード/HTMLは、以下です。

# -*- coding: utf-8 -*-
import re
import time
import requests
import datetime

from flask import render_template
from flask import request
from flask import Flask
from flask import abort
from flask import make_response
from flask import redirect
from flask import url_for

from gevent.pywsgi import WSGIServer

# DBクラス
from DbClass import DbClass

# MAILクラス
from MailClass import MailClass

#Flaskアプリ
app = Flask(__name__)

# 問合せメール送信先
CONST_QA_EMAIL_TO='manager@reasvr.com' 

# QAをDBに保存する関数
def SaveDb(dt,name,email,comment):
    id = 0

    db = DbClass()
        
    if db.Connect() == True :

        id=db.InsertQA_Tbl(dt,name,email,comment)            

        db.Disconnect()

    return id


# QAメールの送信関数
def SendUserQAMail(id,dt,name,email,comment):
    result = False

    try:
        Mail = MailClass()
        if Mail.Connect('',0,'','') == True :

            msg=Mail.CreateMail(CONST_QA_EMAIL_TO,id,dt,name,email,comment)
            Mail.SendMail(msg)
            Mail.Disconnect()
            result = True
    except:
            result = False

    return result


@app.route('/', methods=['GET', 'POST'])
def index():
    return redirect(url_for('user_QA'))


# 問い合わせ画面
@app.route('/user_QA', methods=['GET', 'POST'])
def user_QA():

    html = 'user_QA.html'
    return render_template(html)


@app.route('/send_user_QA', methods=['GET', 'POST'])
def send_user_QA():

    if request.method == 'POST':
        name = request.form['name']
        email = request.form['email']
        comment = request.form['comment']
    else:
        name = request.args.get('name')
        email = request.args.get('email')
        comment = request.args.get('comment')

    if name == None :
        name = ''

    if email == None :
        email = ''
    
    if comment == None :
        comment = ''

    if name == '' or email == '' or comment == '':
        message = 'お名前、メールアドレス、お問い合わせ内容を入力してください'
        html = 'user_QA.html'
        return render_template(html,message=message)
    
    # QAをDBに保存する
    dt = datetime.datetime.now()
    id=SaveDb(dt,name,email,comment)

    if id > 0:
        # QAメールを送信する
        result=SendUserQAMail(id,dt,name,email,comment)
        if result == True:

            message = 'お問合せありがとうございました'
            html = 'result_user_QA.html'
            return make_response(render_template(html,message=message))

    message = 'もう一度、お問合せ下さい'
    html = 'user_QA.html'
    return make_response(render_template(html,message=message))


if __name__ == '__main__':
    app.debug = True

    host='127.0.0.1'
    port = 5000

    host_port = (host, port)
    server = WSGIServer(
       host_port,
       app
    )
    server.serve_forever()
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- inital scale -->
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="/static/common.css" />

<script>

    // -------------------------------------------------------------------
    // メールアドレスチェック関数
    // -------------------------------------------------------------------
    function CheckMailAddress( mail ) {
        var mail_regex1 = new RegExp( '(?:[-!#-\'*+/-9=?A-Z^-~]+\.?(?:\.[-!#-\'*+/-9=?A-Z^-~]+)*|"(?:[!#-\[\]-~]|\\\\[\x09 -~])*")@[-!#-\'*+/-9=?A-Z^-~]+(?:\.[-!#-\'*+/-9=?A-Z^-~]+)*' );
        var mail_regex2 = new RegExp( '^[^\@]+\@[^\@]+$' );
        if( mail.match( mail_regex1 ) && mail.match( mail_regex2 ) ) {
            // 全角チェック
            if( mail.match( /[^a-zA-Z0-9\!\"\#\$\%\&\'\(\)\=\~\|\-\^\\\@\[\;\:\]\,\.\/\\\<\>\?\_\`\{\+\*\} ]/ ) ) { return false; }
            // 末尾TLDチェック(〜.co,jpなどの末尾ミスチェック用)
            if( !mail.match( /\.[a-z]+$/ ) ) { return false; }
            return true;
        } else {
            return false;
        }
    }

    // 入力チェック
    function CheckInput() 
    {
    
        var error = "";

        if(document.form_cond.name.value == "")
        {
            error = "お名前が入力されていません";
        }
        else if(document.form_cond.email.value == "")
        {
            error = "メールアドレスが入力されていません";
        }
        else if(document.form_cond.comment.value == "")
        {
            error = "お問合せ内容が入力されていません";
        }

        // 入力値のチェック
        if(error == "")
        {

            if(CheckMailAddress( document.form_cond.email.value ) == false)
            {
                error = "正しいメールアドレスを入力してください";
                document.form_cond.email.value = "";
            }

        }
    
        if(error != "")
        {
            alert(error);
        }
        else
        {
            // 送信
            document.form_cond.submit();
        }
    }
</script>

</head>

<body>

<div id="condition" class="centering_parent" >
<label class="error_label">【お問合せ】</label>
<br>
<label class="error_label">{{ message }}</label>
<br>


<form action="/send_user_QA" method="post" name="form_cond" class="form-inline">

    <ul>
        <li class="title">
            <label for="title">以下を入力してください </label>
            <br>
            <br>
        </li>

        <li class="name">
            <input type="text" class="user_textbox" id="user" name="name" maxlength="24" size="24" placeholder="お名前(必須)">
        </li>

        <br>

        <li class="email">
            <input type="text" class="user_textbox" id="user" name="email" maxlength="24" size="24" placeholder="メールアドレス(必須)">
        </li>

        <br>
        <li class="comment">
            <label for="comment_label" class="comment_label">【お問合せ内容】(必須)</label>
            <br>
            <textarea class="comment_textbox" id="comment_textbox" name="comment" rows="10" cols="60"></textarea>
        </li>

        <br>
        <li class="submit">
            <br>
            <a href="#" class="btn-flat-border" onclick="CheckInput();">問合わせる</a>
        </li>

    </ul>

</form>

<br>
<br>

<ul class="comment" class="centering_parent" >
    <a href="/"><label for="regist">戻る</label></a>        
</ul>

</div>

</body>
</html>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- inital scale -->
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="/static/common.css" />
</head>

<body>

<div id="condition" class="centering_parent" >
    <br>
    <label>{{ message }}</label>
    <br>
    <br>
    <a href="/"><label>戻る</label></a>
</div>

</body>
</html>
@charset "UTF-8";

body{
    -webkit-text-size-adjust: 100%;
  }

.centering_parent {
    text-align:  center;        /* 中央寄せ */
}

  
.user_textbox{
    position: relative;
    display: block;
    width: 150px;
    margin-top: 0px;
    padding: 10px;
    border: solid;
    border-radius: 5px;
    font-size: 12px;
    color: #a0a0a0;
    outline: none;
    margin-left: auto;
    margin-right: auto;
    text-align: left;
}


.password_textbox{
    position: relative;
    display: block;
    width: 150px;
    margin-top: 0px;
    padding: 10px;
    border: solid;
    border-radius: 5px;
    font-size: 12px;
    color: #a0a0a0;
    outline: none;
    margin-left: auto;
    margin-right: auto;
    text-align: left;
}



.btn-flat-border {
    display: inline-block;
    padding: 5px;
    text-decoration: none;
    color: #67c5ff;
    border: solid 2px #67c5ff;
    border-radius: 3px;
    transition: .4s;
    width: 120px;
    font-size: 14px;
  }
  
  .btn-flat-border:hover {
    background: #67c5ff;
    color: white;
  }


.submit{
    width: 200px;
    font-size: 18px;
    margin-left: auto;
    margin-right: auto;
    text-align: center;
}


.comment{
    width: 250px;
    font-size: 18px;
    margin-left: auto;
    margin-right: auto;
    text-align: center;
}



ul li {
    list-style: none;
    display: inline;
    text-align: center;

}



ul li {
    list-style: none;
    display: inline;
    text-align: center;
}

label {
    float: none;
    font-size: 14px;
    color: #a0a0a0;
    width: 200px;
    display: inline;
}

.error_label {
    float: none;
    font-size: 14px;
    color: #f85104;
    width: 200px;
    display: inline;
}


ul {
    width: 300px;
    margin: 0 auto;
    display: inline;
}


input{
    display: inline;
}

form{
    display: inline;
}


div {text-align:center;}

table{
    width: 100%;
    border-spacing: 0;
    width:300px;
    text-align: center;
  }
  
  table th{
    border-bottom: solid 2px #fb5144;
    padding: 10px 0;
    width: 150px;
    text-align: center;
    font-size: 18px;
    color: #a0a0a0;
  }
  
  table td{
    border-bottom: solid 2px #ddd;
    text-align: center;
    padding: 10px 0;
    width: 150px;
    font-size: 22px;
    color: #a0a0a0;
  }

body {
    position: static;
    overflow: auto;
    height: 100vh; /* これを追加 */
}



MySQLと接続するDBクラス(DbClass)は以下のようなものです。

MySQLインスタンスのローカルIPアドレス、ポート(3306)、データベース名、ユーザ名、パスワード、文字コードなど、一式を指定して、接続し、テーブル(QA_Tbl)にレコードを追加します。

# -*- coding: utf-8 -*-
import mysql.connector
from mysql.connector import errorcode

# DB関連定数  ★GCP
CONST_DB_HOST = '10.74.128.3'   # MySQLインスタンスのローカルIPアドレス
CONST_DB_PORT = 3306            # MySQLインスタンスのポート
CONST_DB_NAME = 'TestDB'        # データベース名
CONST_DB_USER = 'user001'       # ユーザ名
CONST_DB_PASSWORD = 'xxxxxxxx'  # ユーザのパスワード
CONST_DB_CHARSET = 'utf8'       # 文字コード


# DBクラス
class DbClass:
    _cnn = ""
    _cur = ""

    def Connect(self):
        try:

            self._cnn = mysql.connector.connect(host=CONST_DB_HOST,
                                      port=CONST_DB_PORT,
                                      db=CONST_DB_NAME,
                                      user=CONST_DB_USER,
                                      password=CONST_DB_PASSWORD,
                                      charset=CONST_DB_CHARSET,
                                      auth_plugin='mysql_native_password'
                                      )
            self._cnn.autocommit = True
            self._cur = self._cnn.cursor(prepared=True)
            return True

        except (mysql.connector.Error) as e:
            return False

    def InsertQA_Tbl(self,dt,name,email,comment):

        try:

            # レコードの登録
            sql = 'insert into QA_Tbl SET dt = ?,name = ?,email = ? ,comment =?;'
            self._cur.execute(sql,(dt,name,email,comment)) 

            id = self._cur.lastrowid
            return id

        except (mysql.connector.Error) as e:
            return 0


    def Disconnect(self):
        # データベースから切断
        if self._cur != "":
            self._cur.close()
        if self._cnn != "":
            self._cnn.close()

    def __init__(self):
        self._cnn = ""
        self._cur = ""
                
    def __del__(self):
        self._cnn = ""
        self._cur = ""

if __name__ == '__main__':

    row_dic = {}
    print(len(row_dic))

    # test
    db = DbClass()
    db.Connect()
    
    row_dic = {}
    row_dic['dt'] = 0
    row_dic['name'] = 'test'
    row_dic['email'] = 'test@test'
    row_dic['comment'] = 'test'

    id = db.InsertQA_Tbl(row_dic)

    db.DisConnect()


SendGridと接続するMailクラス(MailClass)は以下のようなものです。
メール送信のSmtpLibを使って、SendGridと接続し、メール送信します。

その際、Postfixの動作するローカルアドレスとポート、SendGridのアカウントとパスワード、申請した送信元ドメインを指定します。
直接、インターネット上のメールサーバと接続するときと違って、SMTP-AUTHによる認証は不要です。

# -*- coding: utf-8 -*-
import smtplib
import email
from email.message import EmailMessage
from email.mime.text import MIMEText
import datetime

#SendGrid  ★GCP
CONST_SERVER = 'localhost'                      # Postfixが動作するUbuntuのローカルアドレス
CONST_PORT = 25                                 # Postfixのポート
CONST_ACCOUNT = 'XXXXXXXX@kke.com'              # SendGridのアカウント
CONST_PASSWORD = 'XXXXXXXXXX'                   # SendGridのアカウントのパスワード
CONST_FROM = 'test@test'                        # SendGrid登録時に申請した送信元ドメインのメールアドレス
CONT_SMTP_AUTH = 'no'                           # SMTP-AUTHは使わない


# Mailクラス
class MailClass:
    _smtpobj = None

    def Connect(self,server = CONST_SERVER,port=CONST_PORT,account=CONST_ACCOUNT,password=CONST_PASSWORD):

        try:

            #デフォルト
            if server == '':
                server = CONST_SERVER
            if port == 0:
                port = CONST_PORT
            if account == '':
                account = CONST_ACCOUNT
            if password == '':
                password = CONST_PASSWORD

            self._smtpobj = smtplib.SMTP(server, port)
            self._smtpobj.ehlo()
            self._smtpobj.starttls()
            self._smtpobj.ehlo()

            if CONT_SMTP_AUTH == 'yes':
                self._smtpobj.login(account,password)

            return True

        except (smtplib.SMTPHeloError,
                smtplib.SMTPAuthenticationError,
                smtplib.SMTPException
               ) as e:
            if self._smtpobj != None:
                self._smtpobj.quit()
                self._smtpobj = None

            return False
 
    def Disconnect(self):
        if self._smtpobj != None:
            self._smtpobj.close()


    def CreateMail(self,to,id,dt,name,user_email,comment):


        body = '問合せID:'+str(id)
        body += '\n'        
        body += '日時:'+dt.strftime('%Y-%m-%d %H:%M:%S')
        body += '\n'        
        body += '名前:'+name
        body += '\n'        
        body += 'メールアドレス:'+user_email
        body += '\n'        
        body += '【内容】'
        body += '\n'        
        body += comment

        charset = "utf-8"
        msg = MIMEText(body, "plain", charset)
        msg.replace_header("Content-Transfer-Encoding", "base64")

        msg['Subject'] = 'QAが届きました'
        msg['From'] = CONST_FROM
        msg['To'] = to
        send_dt=email.utils.formatdate()
        msg['Date'] = send_dt

        return msg


    def SendMail(self,msg):
        try:
            self._smtpobj.send_message(msg)        
            return True
        except Exception as e:
            return False



    def __init__(self):
        self._smtpobj = None
                
    def __del__(self):
        self._smtpobj = None


if __name__ == '__main__':

    Mail = MailClass()

    Mail.Connect('',0,'','')

    to ='aaa@bbb'
    id=1
    dt= datetime.datetime.now()
    name='test'
    email='test@test'
    comment='test'

    msg=Mail.CreateMail(to,id,dt,name,email,comment)

    Mail.SendMail(msg)

    Mail.Disconnect()

⑤Python+Flask のWebアプリケーションとApacheとの連結

最後に、 Python+Flask のWebアプリケーションをApacheに連結します。

・ Python+Flask のWebアプリケーション 側の設定

以下のPyhtonコードを記載したファイル(WSGIスクリプト:QA.wsgi)を作成します。

import sys

# WebアプリケーションのPyhton+Flaskのソースコードを保管しているディレクトリのパスを指定
sys.path.insert(0, '/home/swata001/qa')

# QA.pyの中で定義したアプリケーションインスタンス("app")を定義する
from QA import app as application

・Apache側の設定

/etc/apache2/sites-available配下に以下のファイル(flask.conf)を作成します。
これによって、HTTPの80ポートでブラウザからApacheにアクセスし、作成したPaython+FlaskのWebアプリケーションにアクセス可能となります。

このファイルの中で、上記で作成したWSGIスクリプト:QA.wsgiの指定、Pythonの各種パッケージライブラリがインストールされているパスを指定、前述した~/.local/bin/mod_wsgi-express install-moduleの出力結果の追記などをします。

<VirtualHost *:80>

  ServerName <ホスト名>.<ドメイン名>
  ServerAlias www.<ホスト名>.<ドメイン名>

  # Webアプリケーションの格納ディレクトリ
  DocumentRoot "/home/swata001/qa"

  # WSGIスクリプトの指定                                                                                                                                                                        
  WSGIScriptAlias / "/home/swata001/qa/QA.wsgi"

  # 自作したアプリケーション格納先。実行・読み取り権限の指定(すべて許可)                                                                                                                                        
  <Directory /home/swata001/qa>
     # Apache2.4系と2.2系で、記載が微妙に変わります。(これは2.4)                                                                                                                                   
     Require all granted
  </Directory>

RewriteEngine on
RewriteCond %{SERVER_NAME} =www.icebreak.itresourcetech.net [OR]
RewriteCond %{SERVER_NAME} =icebreak.itresourcetech.net
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

# Pythonの各種パッケージライブラリがインストールされているパスを指定する
WSGIPythonPath /home/swata001/anaconda3/lib/python3.8/site-packages
WSGIApplicationGroup %{GLOBAL}

#  ~/.local/bin/mod_wsgi-express install-moduleの出力結果をコピペする
LoadModule wsgi_module "/usr/lib/apache2/modules/mod_wsgi-py38.cpython-38-x86_64-linux-gnu.so"
WSGIPythonHome "/home/swata001/anaconda3"

また、HTTPの443ポート(HTTPS)でアクセスする場合、RSAの鍵ペアを作成し、設定する必要があります。
無料のLetsencryptを利用し、RSAの鍵ペアを生成し、Apacheに設定します。

以下の手順を実施します。その際、<ホスト名>.<ドメイン名>を自分のものを指定します。
途中で、認証のために、DNSサーバのTXTレコードを追加する旨の指示がありますので、指定のテキストを記載したTXTレコードをDNSサーバに設定します。(認証が終われば、削除)

「Ubuntu 20.04でLet’s Encryptを使用してApacheを保護する方法」https://www.digitalocean.com/community/tutorials/how-to-secure-apache-with-let-s-encrypt-on-ubuntu-20-04-ja

その後、 再度、 /etc/apache2/sites-available配下に以下のファイル(flask-le-ssl.conf)を作成します。
これによって、HTTPSでブラウザからApacheにアクセスし、作成したPaython+FlaskのWebアプリケーションにアクセス可能となります。

<IfModule mod_ssl.c>
<VirtualHost *:443>

  ServerName <ホスト名>.<ドメイン名>
  ServerAlias www.<ホスト名>.<ドメイン名>

  # Webアプリケーションの格納ディレクトリ
  DocumentRoot "/home/swata001/qa"

  # WSGIスクリプトの指定                                                                                                                                                                        
  WSGIScriptAlias / "/home/swata001/qa/QA.wsgi"

  # 自作したアプリケーション格納先。実行・読み取り権限の指定(すべて許可)                                                                                                                                        
  <Directory /home/swata001/qa>
     # Apache2.4系と2.2系で、記載が微妙に変わります。(これは2.4)                                                                                                                                   
     Require all granted
  </Directory>

# letsencryptで生成されたRSAの鍵ペアなどのパス
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/icebreak.itresourcetech.net/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/icebreak.itresourcetech.net/privkey.pem

</VirtualHost>
</IfModule>

以下のコマンドで、Apacheを起動します。

 sudo systemctl restart apache2

■ ステップ5)GCPのWebアプリケーションにブラウザからアクセス

インターネットを経由して、ブラウザからGCPのWebアプリケーションにアクセスするには、DNSの設定が必要です。

外部のDNSサービスとして、Xserverを利用する場合、Aレコードを以下のように追加設定する必要があります。

 <ホスト名>.<ドメイン名>        A     <GCEのUbuntuの外部IPアドレス>
 www. <ホスト名>.<ドメイン名>     A     <GCEのUbuntuの外部IPアドレス>

注意点としては、 GCEのUbuntuの外部IPアドレス は、VMインスタンスの開始・停止の度に変わります。(エフェメラル)そのため、静的IPアドレスに変更し、固定とする必要があります。
固定IPとするには、GCPのダッシュボードからVPCネットワーク→外部IPアドレスを選択します。

「静的アドレスを予約」をクリックします。

名前、スタンダード、IPv4、タイプ=リージョン、リージョン=us-west1(オレゴン)、接続先=VMインスタンスの名前を入力し、予約をクリックします。


種類が「静的」に変更され、外部アドレスに固定のIPアドレスが付与されます。
同時にVMインスタンスのGCEのUbuntuのIPアドレスも固定の外部IPアドレスに変更されます。

さて、それでは、ブラウザからアクセスしてみます。

 http://<ホスト名>.<ドメイン名>/

あるいは

 https://<ホスト名>.<ドメイン名>/


のURLをブラウザから入力します。すると以下の画面が表示されます。

名前、メールアドレス、コメントを入力し、「問合わせる」をクリックすると、結果が表示されます。

送信先には、以下のメールが送られます。

また、MySQLのデータベース(TestDB)のテーブル(QA_Tbl)を見ると、レコードが登録されています。

以上のようにして、GCPを使って、Python+FlaskのWebアプリケーションを作ることができます。

-Web

執筆者:


comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

関連記事

Zoom REST API

リモート会議を開催するとき、アプリケーションのZoomを使われてる人も多いと思います。Zoomには、Pythonによってプログラミング可能なWeb-APIであるREST APIが用意されています。この …

Webシステム

ネットワークを使ったシステムは、クライアント/サーバ型システムが基本です。クライアント/サーバ型システムとは、ユーザが操作するクライアントと、データを管理し、処理を実行するサーバとの間をネットワークで …

Flask(Python)

WebアプリケーションをPythonを使って手軽に開発できるマイクロフレームワークがFlaskです。Webアプリケーション開発と言えばPHPがありますが、Flaskの最大の特徴は、プログラミング言語の …

GCPでのWebサービスの作り方(Python、Flask、MYSQL、Mail、Apache) 1/2

GCP(Google Cloud Platform)上で、Webサービスを立ち上げるポイントを整理します。オンプレミス(自前でネインターネット接続環境やサーバを調達してシステムを構築)でWebサービス …

決済API(PAY.JPの例)

EC(電子商取引)などインターネットを使ったサービスが増える中、取引の決済処理を担う決済APIも多種多様になってきています。それら決済APIについて、解説します。 ■ 決済APIとは何か 代表的な決済 …