Web

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

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

以下からの続きとなります。
GCPでのWebサービスの作り方(Python、Flask、MYSQL、Mail、Apache) 1/2

■  ステップ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サービスでしたが、GCPのクラウド環境上にゼロから立ち上げる手順を体験できたと思います。かなりの手順ですが、他のクラウド環境も大筋は同様なものと思われます。

これらはただの手順であり、Webサービスを動かす手段でしかありません。
本質は、Webサービスのビジネスモデルをしっかり考え、品質を確保した上でサービをリリースすることですのでお忘れなく。



ソフトウェア開発・システム開発業務/セキュリティ関連業務/ネットワーク関連業務/最新技術に関する業務など、「学習力×発想力×達成力×熱意」で技術開発の実現をサポート。お気軽にお問合せ下さい

-Web

執筆者:


comment

メールアドレスが公開されることはありません。

関連記事

実践入門「gRPC」とは?

HTTPを使ったAPI定義には、REST APIとGraphQLがあります。これらのAPI定義は、外部に公開するための「外向け」のものです。それに対し、「内向け」のプロセス間通信(IPC)のAPI定義 …

PythonによるWeb開発「Flask」入門

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

はじめての「Webシステム」入門

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

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

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

実践入門「スクレイピング」とは?(その2)

次に、seleniumライブラリを使ったスクレイピングについて、解説します。サイトには、ブラウザとセッションを管理するものもあり、セッションがないとアクセスできないようにしているサイトもあります。セッ …

Chinese (Simplified)Chinese (Traditional)EnglishFilipinoFrenchGermanHindiJapaneseKoreanMalayThaiVietnamese