20210117のMySQLに関する記事は10件です。

AWS_WEB3層環境構築②

前回の記事
https://qiita.com/shinichi_yoshioka/items/7226b9ebaad06c569c80
image.png
前回の続きをやっていく。
APサーバとDBサーバはプライベートサブネットに構築する。
プライベートサブネット配置のEC2インスタンス作成にあたって、
"パブリックIP自動割り当てを無効"にしたが
TomcatやMySQLをインストールするのに一時的にインターネットに繋ぎたい。
そもそもプライベートサブネット配置のEC2インスタンスにssh接続できなくて詰んでいる。
対処法を調べたところ、3通りぐらい把握した。
①ElasticIP(EIP)を一時的に割り当て →これは実質パブリックサブネットと変わらない。
②前回構築したWEBサーバを踏み台としてアクセスする →SSH接続はできるが、TomcatやMySQLをインストールするのに面倒。
③NATゲートウェイをパブリックサブネットに配置する →これが一番良いやり方。

ちなみにNATゲートウェイの料金は、東京リージョンで1hあたり0.062USDらしい。
https://aws.amazon.com/jp/vpc/pricing/
施行錯誤の環境構築で時間がかかると思ったので、今回はEIPを使い、一時的にパブリック化する方法を選んだ。
(2台目のDBサーバを構築する際は、NATゲートウェイを使おうと思う)
EIPはAWSアドレスプールから払い出される固定のパブリックIPのこと。
セキュリティグループも一時的に開けないとダメだし、ルートテーブルもインターネットゲートウェイへ向ける。
構築が落ち着いたら、封鎖するので許してほしい。

◆EIPの作成とアタッチ
サービス[VPC]のElasticIPから[Elastic IPアドレスの割り当て]から、
AmazonのIPv4アドレスプールから割り当てを行う。
EIP1.PNG
割り当てられたアドレスをクリックすると、EC2インスタンスに関連付けできる。
EIP2.PNG
ちなみにEIPはEC2インスタンスにアタッチ中は課金されないが、
EIPの払い出しだけしていてEC2にアタッチされていないと課金されるらしい。
EIP3.PNG
ここでは、APサーバとDBサーバそれぞれにEIPを割り当てる。
こんな感じ。
EIP4.PNG
とりあえず、各EC2インスタンスにSSH接続できることは確認した。
AP/DBサーバの構築後処理は以下。
①EIPをデタッチし、EIPを解放
②ルートテーブルからインターネットゲートウェイを削除し、最低限に絞る
③セキュリティグループを必要なプロトコルのみに絞る

◆Nginxのインストール
対象:WEBサーバ
sudo su -
yum update -y
yum install nginx -y
ここでエラーが。
nginx1.PNG
どうやら、AmazonLinuxはインストール方法が違うらしい。
以下コマンドでインストールが開始されたことを確認した。
amazon-linux-extras install nginx1 -y
nginx2.PNG
Nginxの自動起動を有効化にし、サービスを起動。
ステータスがactive(running)になっていることを確認した。
systemctl enable nginx.service
systemctl start nginx.service
systemctl status nginx.service
nginx3.PNG
ブラウザに以下のように入力し、Nginxのテストページが表示されることを確認した。
http://WEBサーバのパブリックアドレス

◆Tomcatのインストール
対象:APサーバ
sudo su -
yum update -y
yum install tomcat -y
systemctl enable tomcat.service
systemctl start tomcat.service
systemctl status tomcat.service
tomcat1.PNG
tomcatのサービスは正常に動いているが、Web App Containerとしての正常性確認のやり方が不明(調べ中)
過去に自宅VirtualBoxにTomcatを入れて正常性確認をしたが、これはApache Tomcat(WEBサーバ)であって
上記のWeb App Containerとは違う認識。
tomcat2.PNG

◆MySQLのインストール
対象:DBサーバ
sudo su -
yum update -y
yum install mysql -y
MySQL1.PNG
Mysqlをインストールしようとしたら、MariaDBが入ったのだが・・・。
他のEC2インスタンスを確認したところ、Amazon Linuxにはデフォルトでmariadb-libs-5.5.68-1.amzn2.x86_64が入っていて
MySQL互換のMariaDBをインストールしてしまった。
MySQLとMariaDBで競合をおこさないようにアンインストールしておく。
yum remove mariadb-libs -y
rpm -qa | grep -i maria
何も表示されないことを確認した。

次にMySQLをyumでインストールするため、MySQL公式のリポジトリを追加した。
yum localinstall http://dev.mysql.com/get/mysql57-community-release-el7-7.noarch.rpm -y
MySQL2.PNG
yum info mysql-community-server
にて、MySQLのyumリポジトリ追加を確認。
yum -y install mysql-community-server
mysqld --version
にてMySQLのインストールを確認。
MySQL4.PNG

他のサービスと同様にmysqld.serviceが正常に動いていることを確認した。
systemctl enable mysqld.service
systemctl start mysqld.service
systemctl status mysqld.service
MySQL5.PNG
MySQLのrootユーザの初期パスワードは、/var/log/mysqld.logに記載されている。
cat /var/log/mysqld.log | grep temporary
一時的なパスワードなので、rootユーザにログイン後に任意のパスワードに変える。
mysql -u root -p
白塗りの一時パスワードを入力し、rootユーザにログイン。
set password for root@localhost=password('ここに新しいパスワード');
MySQL6.PNG
Query OKと出れば変更完了だが、初期のパスワードポリシーが結構厳しめで
パスワードは大文字・小文字・数字・記号とかにしないとはじかれると思う。
パスワード変更後はいったんMySQLから抜けて、新パスワードでログインできることを確認した。
MySQL7.PNG

長くなってしまったので、第2回はここまで。
久々に有意義な休日を過ごせたと思う。(いつもはゲームして、YouTube見て、見てるうちに寝ちゃって1日終わる)
次回は、APサーバにMySQLドライバーを入れて、WEBサーバとAPサーバとDBサーバを連携したい。
イメージでは、WEBサーバのnginx.confにリバースプロキシの設定を入れて、
Tomcatのserver.xmlにDBサーバのアドレスを記載すれば
連携できるのではないかと思っている。
正直ここから先は何もわかっていないので、次回の記事は結構先になりそうだ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Warning: Illegal string offset ' ' in... の解決方法

今回は、SQLから取得したデータをsmartyを使って、foreachでtable表示させようとした際に発生したエラーが解決した方法をご紹介します。

発生したエラー

Warning: Illegal string offset '出力変数の各カラム名' in...

下記のサイトを参考に解決したのですが、全て英語で書かれた記事なので、正直正確なエラー発生の原因がわかっていません。
どなたか詳しい原因が分かる方いましたらコメントにて教えて頂けると幸いです。
私の場合は、どうやら出力変数のキーを文字列で指定していた為に発生したようです。

・参考サイト
https://stackoverflow.com/questions/9869150/illegal-string-offset-warning-php#:~:text=The%20error%20Illegal%20string%20offset,string%20as%20a%20full%20array.&text=For%20those%20who%20come%20to,about%20it%2C%20as%20I%20was

エラーが発生したコードと修正コード

list2.php(データ取得)修正前

<?php
require_once('../db_connect2/db_connect2.php');
require( dirname( __FILE__ , 3).'/libs/Smarty.class.php' );

$smarty = new Smarty();

$smarty->template_dir = dirname( __FILE__ , 3).'/templates';
$smarty->compile_dir  = dirname( __FILE__ , 3).'/templates_c';
$smarty->config_dir   = dirname( __FILE__ , 3).'/configs';
$smarty->cache_dir    = dirname( __FILE__ , 3).'/cache';

$smarty->escape_html  = true;

try
{
  $sql = 'SELECT stock_id,purchase_date,deadline,stock_name,price,number FROM stocks WHERE 1';
  $stmt = connect()->prepare($sql);
  $stmt->execute();
  $rec = $stmt->fetch(PDO::FETCH_ASSOC); //ここで、結果セットに返された際のカラム名で添字を付けた配列を返したことが原因。
  $dbh = null;
}
catch(Exception $e)
{
  echo "エラー発生:" . htmlspecialchars($e->getMessage(),ENT_QUOTES, 'UTF-8') . "<br>";
  print'ただいま障害により大変ご迷惑をお掛けしております。';
  exit();
}

$smarty->assign('stock', $rec);
$smarty->display('list.tpl');
?>

修正コード

try
{
  $sql = 'SELECT stock_id,purchase_date,deadline,stock_name,price,number FROM stocks WHERE 1';
  $stmt = connect()->prepare($sql);
  $stmt->execute();
  $rec = $stmt->fetch(PDO::FETCH_ASSOC); //ここで、結果セットに返された際のカラム名で添字を付けた配列を返したことが原因。
  $dbh = null;
}

↓

try
{
  $sql = 'SELECT stock_id,purchase_date,deadline,stock_name,price,number FROM stocks WHERE 1';
  $stmt = connect()->prepare($sql);
  $stmt->execute();
  $dbh = null;
}

list.tpl(出力)修正前

<table class = "sorttbl" id = "myTable" border = "2">
    <tr>
      <th class = "radio-th"></th>
      <th class = "purchase_date-th">購入日</th>
      <th class = "stock_name-th">商品</th>
      <th class = "price-th">値段</th>
      <th class = "number-th">数量</th>
      <th class = "deadline-th" onclick = "w3.sortHTML('#myTable','.item', 'td:nth-child(6)')">消費期限&nbsp;<i class = "fa fa-sort"></i></th>
    </tr>

    //出力変数のキーを文字列で指定しているのが原因
    {foreach $stock as $s}
      <tr class = "item">
        <td><input type = "radio" name = "stockid" value = "{$s.stock_id}"></td>
        <td>{$s.purchase_date|date_format:'%Y-%m-%d'}</td>
        <td>{$s.stock_name}</td>
        <td>¥{$s.price}</td>
        <td>{$s.number}</td>
        <td>{$s.deadline|date_format:'%Y-%m-%d'}</td>
      </tr>
    {/foreach}
  </table>

修正コード

{foreach $stock as $s}
  <tr class = "item">
    <td><input type = "radio" name = "stockid" value = "{$s.stock_id}"></td>
    <td>{$s.purchase_date|date_format:'%Y-%m-%d'}</td>
    <td>{$s.stock_name}</td>
    <td>¥{$s.price}</td>
    <td>{$s.number}</td>
    <td>{$s.deadline|date_format:'%Y-%m-%d'}</td>
  </tr>
{/foreach}

↓

{foreach $stock as $s}
  <tr class = "item">
   <td><input type = "radio" name = "stockid" value = "{$s[0]}"></td>
   <td>{$s[1]|date_format:'%Y-%m-%d'}</td>
    <td>{$s[3]}</td>
    <td>¥{$s[4]}</td>
    <td>{$s[5]}</td>
    <td>{$s[2]|date_format:'%Y-%m-%d'}</td>
  </tr>
{/foreach}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerでapache7.4+mysql8環境構築(初期データ入り)

今更ですが、Macで表題の環境を作らなくてはいけなくなったので、構築してみました。
備忘録として書いておきます。

環境

マシン macOS Catalina 10.15.7

構成

ファイル、ディレクトリの構成はざっくりと以下のようにします。

任意のディレクトリ
  │
  ├── docker-compose.yml
  │
  ├── html/
  │   └── index.html
  │
  ├── mysql/
  │   ├── Dockerfile
  │   ├── data/
  │   ├── init/
  │   │   └── init.sql
  │   └── my.cnf
  │
  ├── php-apahce/
      ├── Dockerfile
      └── php.ini

この構築の重要な部分

docker-compose.ymlとDockerfileがこの構築の重要な部分になります。

ファイル名 説明
docker-compose.yml コンテナの構成を定義するもの。コンテナ間通信の定義もできる。
Dockerfile dockerのイメージに対する定義。

docker-compose.ymlの要素

調べて自分が認識している限りだと以下の通り

名称 意味
build Dockerfileがある位置を指定
volumus ローカル内のマウントされる場所:コンテナ内のマウントする場所
ports ポートフォワード
container_name コンテナの名前 docker container lsのname
environment 環境変数?変数名で何を意味するかがなんとなくわかる

Dockerfileの要素

調べて自分が認識している限りだと以下の通り

名称 意味
FROM 何をどのバージョンで
EXPOSE どのポートを使用するか
ADD ローカルファイルをコンテナ内ファイルに追記
CMD コンテナ起動時に実行されるやつ
COPY ローカルファイルをコンテナ内ディレクトリにコピーする
RUN イメージ作成時に呼ばれるやつ。なのでパッケージのインストール等を書く。

構築

本編はここからです。

確認

まずコンテナの状態確認

ksk@ksknoMacBook-Pro work % docker container ls -a
CONTAINER ID   IMAGE             COMMAND                  CREATED       STATUS       PORTS                               NAMES

何もいません

./docker-compose.yml

docker-compose.ymlとは、コンテナの構成を定義するファイル

docker-compose.yml
version: '3'
services:
  php-apache:
    build: ./php-apache/
    volumes:
      - ./html:/var/www/html
    ports:
      - 8080:80
    container_name: web
  mysql:
    build: ./mysql/
    volumes:
      - "./mysql/data:/var/lib/mysql"
      - "./mysql/init:/docker-entrypoint-initdb.d"
    environment:
      - MYSQL_ROOT_PASSWORD=docker
      - MYSQL_DATABASE=mydb
      - MYSQL_USER=appuser
      - MYSQL_PASSWORD=appuser1
    container_name: db
    ports:
      - 3306:3306

ymlに書いている属性?で、自分が理解していることを以下の表に書いてみる
(間違っているところを指摘してくれる優しい人いたら教えてください)

./html/index.php

動作確認するために使用。
とりあえず、DBのデータを表示できれば良しとする。
volumesの定義により、htmlがドキュメントルートとなる。

index.php
<?php
try {
    $db = sprintf('mysql:host=%s:3306;dbname=%s',  'mysql', 'mydb');
    $dbh = new PDO($db, 'appuser', 'appuser1');
    foreach($dbh->query('select * from users') as $row) {
        echo $row['name'] . '<br>';
    }
    $dbh = null;
} catch (PDOException $e) {
    echo $e;
    die();
}
$dbh = null;

hostの指定で「'mysql'」としていますが、これはdocker-compose.ymlのservice名と理解しています。

docker-compose.yml
  mysql:     ←これ!!!
    build: ./mysql/
    volumes:

./mysql/Dockerfile

mysql側のDockerfile
DockerfileとはDockerイメージの定義を書くファイルです。

FROM mysql:8.0

EXPOSE 3306

ADD ./my.cnf /etc/mysql/conf.d/my.cnf

CMD ["mysqld"]

./mysql/init/init.sql

適当なテーブルとデータを詰め込むような記述にしておく

use mydb;

CREATE TABLE users (
  id int(10) unsigned not null auto_increment,
  name varchar(255) not null,
  primary key (id)
);

insert into users(name) values('hogeo');
insert into users(name) values('fugao');

./mysql/my.cnf

my.cnf
[mysqld]
character-set-server=utf8
default_authentication_plugin=mysql_native_password

[mysql]
default-character-set=utf8

[client]
default-character-set=utf8

default_authentication_plugin=mysql_native_passwordについて

mysqlのデフォルト認証プラグインが変わったので、デフォルトの認証プラグインを変更しています。
mysqlの環境変数でユーザ(appuser)作っていますが、mysql_native_passwordという認証プラグインで設定されます。
デフォルトのままだと、phpがmysqlへのアクセスで失敗します。

./php-apache/Dockerfile

色んなサイトを見て参考にさせてもらいました。

FROM php:7.4-apache
COPY ./php.ini /usr/local/etc/php/
RUN apt-get update
RUN apt-get install -y zip unzip vim libpng-dev libpq-dev
RUN docker-php-ext-install pdo_mysql

./php-apache/php.ini

色んなサイトを見て参考にさせてもらいました。

[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"

docker-compose build

上記を作った後、docker-compose.ymlと同階層で以下のコマンド実行

ksk@ksknoMacBook-Pro work % docker-compose build
〜〜〜中略〜〜〜
Successfully built e5b1c15e825e
Successfully tagged work_php-apache:latest
Building mysql
Step 1/4 : FROM mysql:8.0
 ---> d4c3cafb11d5
Step 2/4 : EXPOSE 3306
 ---> Using cache
 ---> e11d55e213ab
Step 3/4 : ADD ./my.cnf /etc/mysql/conf.d/my.cnf
 ---> Using cache
 ---> 6dd70a6b7ecd
Step 4/4 : CMD ["mysqld"]
 ---> Using cache
 ---> c22190479ddf

Successfully built c22190479ddf
Successfully tagged work_mysql:latest

コンテナ作成&起動

ksk@ksknoMacBook-Pro work % docker-compose up -d
Creating web ... done
Creating db  ... done

確認

コンテナの状態確認

ksk@ksknoMacBook-Pro work % docker container ls -a
CONTAINER ID   IMAGE             COMMAND                  CREATED         STATUS         PORTS                               NAMES
b416b97d3f7b   work_mysql        "docker-entrypoint.s…"   2 seconds ago   Up 2 seconds   0.0.0.0:3306->3306/tcp, 33060/tcp   db
9985abb2eb90   work_php-apache   "docker-php-entrypoi…"   2 seconds ago   Up 2 seconds   0.0.0.0:8080->80/tcp                web

コンテナが確認できました

画面確認

http://localhost:8080
こちらへアクセス

qiita_20200117_01.png

以上!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerでapache7.4+mysql8環境構築(初期データ入り)(自分メモ)

今更ですが、Macで表題の環境を作らなくてはいけなくなったので、構築してみました。
備忘録として書いておきます。

環境

マシン macOS Catalina 10.15.7

構成

ファイル、ディレクトリの構成はざっくりと以下のようにします。

任意のディレクトリ
  │
  ├── docker-compose.yml
  │
  ├── html/
  │   └── index.html
  │
  ├── mysql/
  │   ├── Dockerfile
  │   ├── data/
  │   ├── init/
  │   │   └── init.sql
  │   └── my.cnf
  │
  ├── php-apahce/
      ├── Dockerfile
      └── php.ini

この構築の重要な部分

docker-compose.ymlとDockerfileがこの構築の重要な部分になります。

ファイル名 説明
docker-compose.yml コンテナの構成を定義するもの。コンテナ間通信の定義もできる。
Dockerfile dockerのイメージに対する定義。

docker-compose.ymlの要素

調べて自分が認識している限りだと以下の通り

名称 意味
build Dockerfileがある位置を指定
volumus ローカル内のマウントされる場所:コンテナ内のマウントする場所
ports ポートフォワード
container_name コンテナの名前 docker container lsのname
environment 環境変数?変数名で何を意味するかがなんとなくわかる

Dockerfileの要素

調べて自分が認識している限りだと以下の通り

名称 意味
FROM 何をどのバージョンで
EXPOSE どのポートを使用するか
ADD ローカルファイルをコンテナ内ファイルに追記
CMD コンテナ起動時に実行されるやつ
COPY ローカルファイルをコンテナ内ディレクトリにコピーする
RUN イメージ作成時に呼ばれるやつ。なのでパッケージのインストール等を書く。

構築

本編はここからです。

確認

まずコンテナの状態確認

ksk@ksknoMacBook-Pro work % docker container ls -a
CONTAINER ID   IMAGE             COMMAND                  CREATED       STATUS       PORTS                               NAMES

何もいません

./docker-compose.yml

docker-compose.ymlとは、コンテナの構成を定義するファイル

docker-compose.yml
version: '3'
services:
  php-apache:
    build: ./php-apache/
    volumes:
      - ./html:/var/www/html
    ports:
      - 8080:80
    container_name: web
  mysql:
    build: ./mysql/
    volumes:
      - "./mysql/data:/var/lib/mysql"
      - "./mysql/init:/docker-entrypoint-initdb.d"
    environment:
      - MYSQL_ROOT_PASSWORD=docker
      - MYSQL_DATABASE=mydb
      - MYSQL_USER=appuser
      - MYSQL_PASSWORD=appuser1
    container_name: db
    ports:
      - 3306:3306

ymlに書いている属性?で、自分が理解していることを以下の表に書いてみる
(間違っているところを指摘してくれる優しい人いたら教えてください)

./html/index.php

動作確認するために使用。
とりあえず、DBのデータを表示できれば良しとする。
volumesの定義により、htmlがドキュメントルートとなる。

index.php
<?php
try {
    $db = sprintf('mysql:host=%s:3306;dbname=%s',  'mysql', 'mydb');
    $dbh = new PDO($db, 'appuser', 'appuser1');
    foreach($dbh->query('select * from users') as $row) {
        echo $row['name'] . '<br>';
    }
    $dbh = null;
} catch (PDOException $e) {
    echo $e;
    die();
}
$dbh = null;

hostの指定で「'mysql'」としていますが、これはdocker-compose.ymlのservice名と理解しています。

docker-compose.yml
  mysql:     ←これ!!!
    build: ./mysql/
    volumes:

./mysql/Dockerfile

mysql側のDockerfile
DockerfileとはDockerイメージの定義を書くファイルです。

FROM mysql:8.0

EXPOSE 3306

ADD ./my.cnf /etc/mysql/conf.d/my.cnf

CMD ["mysqld"]

./mysql/init/init.sql

適当なテーブルとデータを詰め込むような記述にしておく

use mydb;

CREATE TABLE users (
  id int(10) unsigned not null auto_increment,
  name varchar(255) not null,
  primary key (id)
);

insert into users(name) values('hogeo');
insert into users(name) values('fugao');

./mysql/my.cnf

my.cnf
[mysqld]
character-set-server=utf8
default_authentication_plugin=mysql_native_password

[mysql]
default-character-set=utf8

[client]
default-character-set=utf8

default_authentication_plugin=mysql_native_passwordについて

mysqlのデフォルト認証プラグインが変わったので、デフォルトの認証プラグインを変更しています。
mysqlの環境変数でユーザ(appuser)作っていますが、mysql_native_passwordという認証プラグインで設定されます。
デフォルトのままだと、phpがmysqlへのアクセスで失敗します。

./php-apache/Dockerfile

色んなサイトを見て参考にさせてもらいました。

FROM php:7.4-apache
COPY ./php.ini /usr/local/etc/php/
RUN apt-get update
RUN apt-get install -y zip unzip vim libpng-dev libpq-dev
RUN docker-php-ext-install pdo_mysql

./php-apache/php.ini

色んなサイトを見て参考にさせてもらいました。

[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"

docker-compose build

上記を作った後、docker-compose.ymlと同階層で以下のコマンド実行

ksk@ksknoMacBook-Pro work % docker-compose build
〜〜〜中略〜〜〜
Successfully built e5b1c15e825e
Successfully tagged work_php-apache:latest
Building mysql
Step 1/4 : FROM mysql:8.0
 ---> d4c3cafb11d5
Step 2/4 : EXPOSE 3306
 ---> Using cache
 ---> e11d55e213ab
Step 3/4 : ADD ./my.cnf /etc/mysql/conf.d/my.cnf
 ---> Using cache
 ---> 6dd70a6b7ecd
Step 4/4 : CMD ["mysqld"]
 ---> Using cache
 ---> c22190479ddf

Successfully built c22190479ddf
Successfully tagged work_mysql:latest

コンテナ作成&起動

ksk@ksknoMacBook-Pro work % docker-compose up -d
Creating web ... done
Creating db  ... done

確認

コンテナの状態確認

ksk@ksknoMacBook-Pro work % docker container ls -a
CONTAINER ID   IMAGE             COMMAND                  CREATED         STATUS         PORTS                               NAMES
b416b97d3f7b   work_mysql        "docker-entrypoint.s…"   2 seconds ago   Up 2 seconds   0.0.0.0:3306->3306/tcp, 33060/tcp   db
9985abb2eb90   work_php-apache   "docker-php-entrypoi…"   2 seconds ago   Up 2 seconds   0.0.0.0:8080->80/tcp                web

コンテナが確認できました

画面確認

http://localhost:8080
こちらへアクセス

qiita_20200117_01.png

以上!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS Lambdaでコンテナデプロイする方法

はじめに

随分前になりますが、AWS Lambdaでコンテナデプロイがサポートされました。
AWS Lambda now supports container images as a packaging format

今回は、AWS Lambdaにコンテナのイメージをデプロイする方法について紹介します!

対象

  • AWS Lambdaの新機能について知りたい人
  • コンテナデプロイの流れを知りたい人

YouTube動画

動画で確認したい方は、こちらを利用ください!
*撮影は1ヶ月以上前のものですが、大きく変わったところはありません。
【YouTube動画】実践! Lambdaでコンテナデプロイをする方法!!
実践! Lambdaでコンテナデプロイをする方法!!

コンテナのデプロイ条件

Lambdaに、コンテナデプロイがサポートされましたが、コンテナなら何でも良いという訳ではありません。
AWSが提供しているLambda用のRuntime APIに準拠している必要があり、以下のいずれかの方法でコンテナを作る必要があります。

方法1: AWS提供のベースイメージを使う
方法2: Runtime APIが入っているイメージを使う

以下のサイトから使いたいランタイムを選択して、利用できます。
Runtime support for Lambda container images

具体例

今回はベースイメージを利用して、実際にLambdaにコンテナデプロイしてみます。
まず、簡単なNode.jsのサンプルを確認して、次に実践的なRubyのサンプルを見ていきます。

Node.jsのサンプル

簡単なサンプルを書くとこのようになります。

# ベースイメージの取得
FROM public.ecr.aws/lambda/nodejs:12

# Lambda関数を定義しているapp.jsをLambda実行時のルートディレクトリに置く
COPY app.js ${LAMBDA_TASK_ROOT}

# app.jsのhandler関数を実行
CMD [ "app.handler" ]

Rubyのサンプル

このサンプルはLambdaからMySQLに接続するためのLambda関数を作ります。
コンテナをサポートする前は、native extenstion関連で面倒な手順が必要でしたが、コンテナをサポートしたことで簡単に使えるようになりました。

FROM amazon/aws-lambda-ruby:2.7

WORKDIR ${LAMBDA_TASK_ROOT}

# MySQL関連で依存しているものをインストール
RUN yum install -y mysql-devel gcc-c++ make

COPY . ${LAMBDA_TASK_ROOT}

RUN bundle config --global silence_root_warning 1
RUN bundle config set path 'vendor/bundle'
RUN bundle install

CMD ["app.App::Handler.process"]

ローカルでLambdaを動かす

コンテナ化したことで、ローカルで実際に試すことができます。

9000番ポートを開放して試したい場合は次のようにします。

docker run -p 9000:8080 <image name>

そして、以下のようにPOSTすることで、実際に確認できます。
ここでの、/2015-03-31/functions/function/invocations"は固定です。

curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" \
-d '{"payload":"hello world!"}'

デプロイ

まずはコンテナイメージをAmazon ECRにデプロイする必要があります。
今回は割愛します。以下が詳しいです。
Docker イメージをプッシュする

Lambdaの関数の作成方法を確認すると、コンテナイメージという項目ができているので、そちらを選択して使います。
_2020-12-07_20.20.44.png

まとめ

今回はAWS Lambdaにコンテナをデプロイする方法について解説しました。
この記事を通してざっくり理解していただくと、自分で設定する時にスムーズだと思います。

また、AWS Lambdaでコンテナを使った場合は、最初の起動で2 ~ 5秒程度かかってしまいますが、それ以降はスムーズに起動します。
AWS Lambdaの利用の幅が広がる新機能なので、ぜひ遊んでみてください!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MYSQLコマンド

ポスグレとごっちゃになってしまっているので、まとめてみました。

テーブル作成

mysql> CREATE DATABASE `testtable`;

テーブル確認

show databases();

結果

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql_test         |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

このような表記が出る。

現在接続しているDBの確認

mysql> SELECT database();

DB接続

mysql> use mysql_test;
Database changed

テーブル作成

mysql >  CREATE TABLE テーブル名(カラム名 データ型, カラム名 データ型)

テーブルの確認

mysql > show tables;

テーブルにデータをロードする

INSERT INTO テーブル名 VALUES (カラム1, カラム2, カラム3)

複数入れる場合

mysql > INSERT INTO pokemon VALUES
    (1, 'Andy', 35 , America, 'Ramen')
 ,(2, 'Betty', 26, Canada, 'Sushi')
 ,(3, 'Carol', 21, America, 'Sushi')

データを削除

DELETE FROM テーブル名

テーブルを削除

mysql > DROP FROM テーブル名;

DBを消す

mysql > DROP DATABASE データベース名;

テーブルのデータ検索

SELECT * FROM テーブル名; 

必要なカラムの値を検索

SELECT カラム名1, カラム名2 FROM テーブル名; 

条件を指定してデータを検索

SELECT * FROM テーブル名 WHERE 条件文;

mysql> SELECT * FROM user WHERE food = 'Sushi';
+------+---------------+---------------------------+------------------------+
| id   | name          | country|       Food                                |                  
+------+---------------+---------------------------+------------------------+
|    1 | Betty         | America| Sushi                                     |                
|    7 | Yusuke        | Japan  | Sushi                                     |                 
|   21 | Zack          | India  | Sushi                                     |            
+------+---------------+---------------------------+------------------------+
3 rows in set (0.16 sec)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

データベースとは?その役割や種類まとめ

データベースが一体どんなものであるのか?
初心者にも分かりやすく解説。

データベースとは?

データベースとは、簡単にいえば「情報の集合体」。
必要な情報を取り出したり、平均値を算出してみたり、いろいろな活躍をしてくれる。

例えば、以下のような情報は、データベースで活用されることが多い。

  • 銀行の個人情報
  • 顧客の名前や連絡先
  • ゲームユーザーのIDやパスワード

など、幅広い情報が、データベースに登録されている。

データベースの種類

実はデータベースといっても、以下のようにいくつかの種類が存在する。

  • 階層型データベース
  • XMLデータベース
  • リレーショナルデータベース
  • NOSQLデータベース
  • オブジェクト指向データベース

など。
それぞれ簡単な特徴を紹介します。

階層型データベース

親データと子データの関係から成り立つデータベース。
例えば、会社などの組織図が当てはまる。

XMLデータベース

情報をXML形式で管理するデータベース。
※XML形式=機械に情報を伝えるための言語。

リレーショナルデータベース

リレーショナルデータベース(RDB)は、SQL言語を用いて扱う、現在主流のデータベース。
詳細は後述します。

NOSQLデータベース

リレーショナルデータベースでは管理しにくいデータを扱うためのデータベース。
比較的、データの整合性に対してゆるいが、機能はそこまで多くない。

大量のデータを、高速処理できるのが強み。

オブジェクト指向データベース

オブジェクト形式で扱うデーターベース。
関連性のあるデータや処理方法を、オブジェクト(箱)に格納する。

主流のデータベース

先ほど紹介したように、主流のデータベースは、リレーショナルデータベース(RDB)になる。
Relationalという名前の通り、各データ間には何かしらの繋がりが存在する。

表自体をテーブルと呼び、テーブル同士で関係を定めたり、複数のテーブルから新しい表を作ったりできる。

リレーショナルデータベースの操作

リレーショナルデータベースを扱うには、SQL文の知識が必要。
SQLの基本操作は、以下の通り。

  • 検索
  • 登録
  • 更新
  • 削除

もちろん他にも機能はあるが、基本操作は上記4つ。

データ検索をはじめ、新しく登録したり更新したり、削除することも可能!

データベース管理システム(DBMS)

リレーショナルデータベースを扱うには、SQL文だけでなく、管理システムを使う必要がある。

以下が、主な管理用のソフトウェア。

  • oracle
  • SQL server
  • DB2
  • postgreSQL
  • MySQL
  • FireBird

など。

まとめ

以上が、データベースに関する簡単なまとめ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Cloud9でWordPress環境を構築 3

WordPressの学習&AWSに触れるのを目的として
AWS Cloud9でWordPress環境を構築するまでの備忘録。環境構築完了。

ここまでやったこと

  • Cloud9環境立ち上げ
  • MySQLセットアップ
  • Apache、MySQLサービス起動
  • スナップショット作成

この記事の目次

  • WordPressセットアップ
    • 前準備
    • インストール

基本これに従う。
https://docs.aws.amazon.com/ja_jp/cloud9/latest/user-guide/sample-wordpress.html

WordPressセットアップ

前準備

WordPressをダウンロード&展開する。

wget http://wordpress.org/latest.tar.gz
tar -xzvf latest.tar.gz

wp-config-sample.phpwp-config.phpに名前変更して利用する。

cd wordpress
mv wp-config-sample.php wp-config.php

wp-config.php内の3箇所をMySQLで作成したデータベースに合わせる。

define( 'DB_NAME', 'データベース名' );
define( 'DB_USER', 'ユーザ名' );
define( 'DB_PASSWORD', 'パスワード' );

Amazonのサイトに記載はないが、セキュリティ的な対応をしておく。
次の値をサイトでランダムに生成して書き換える。
https://api.wordpress.org/secret-key/1.1/salt/

define('AUTH_KEY', 'XXXXX');
define('SECURE_AUTH_KEY', 'XXXXX');
define('LOGGED_IN_KEY', 'XXXX');
define('NONCE_KEY', 'XXXX');
define('AUTH_SALT', 'XXXX');
define('SECURE_AUTH_SALT', 'XXXX');
define('LOGGED_IN_SALT',   'XXXX');
define('NONCE_SALT', 'XXXX');

インストール

index.phpをエディタで開いてメインメニューバーからRunを実行する。
メインメニューバーのPreview > Preview Running Application を実行する。
Not Foundのエラー画面が出る。これは正常。
スクリーンショット 2021-01-17 10.07.31.png

ブラウザのパスに/wordpress/を追加する。
これでインストール画面が出るらしいが、ずっとぐるぐるして画面が表示されない。
スクリーンショット 2021-01-17 10.07.31のコピー.png

追加するURLを/wordpress/readme.htmlに変更する。画面が表示される。
(ここが分からず、色々いじって何回かCloud9の環境を作成しなおした……)
スクリーンショット 2021-01-17 10.29.33.png

install.phpへのリンクをクリックしてインストールを進める。
スクリーンショット 2021-01-17 10.41.58.png

ようやくWordPressのインストールまで完了した。
AWSの用語が分からなかったり、プリインストールのMySQLが動かなかったりで
結構時間がかかってしまった……。

今後はこの環境を使ってWordPressの学習を進める。

前の記事へのリンク
Cloud9でWordPress環境を構築 1
Cloud9でWordPress環境を構築 2

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MySQLで取得したデータを、EJSでWebブラウザに出力する

はじめに

Node.js + Express で作る Webアプリケーション 実践講座を参考にしながら、
データベース(以下DB)内のデータを、Webブラウザに表示する方法を記事にしました。

なお、ここではNode.jsのテンプレートエンジンであるEJSと、RDB(リレーショナルデータベース)であるMariaDB(MySQL)を利用します。

(上記講座ではMongoDBが利用されていますが、本記事ではMySQLに置き換えました。)

実行環境

  • Node.js v12.16.3
  • Express 4.16.1
  • 10.4.11-MariaDB

対象者

  • JavaScriptの文法自体は学んだけど、Web技術はまだほとんど学べていない人
  • かんたんなCRUD操作に関するSQLを理解している人

本記事でわかること

  • サーバーサイド言語Node.js & フレームワークExpressを使い、Hello Worldする方法
  • ExpressとMariaDB(MySQL)の連携方法
  • ExpressとMariaDB(MySQL)を使い、DB内のデータをWebブラウザ上に出力する方法

対象のUdemy講座で学んだこと

対象の講座で学んだことのうち、特に本記事へ反映する内容は以下となります。

  • パッケージマネージャであるnpmを使い、ミドルウェアやフレームワークを導入する方法
  • EJSの構文の使い方
  • Expressでのルーティング方法(特に関数の引数に関して)

EJSとは

EJSは、テンプレートエンジンと呼ばれるもののひとつで、HTMLの中にプログラム言語を埋め込むことができます。
特にEJSにおいては、HTML文書の中に<% %>, <%= %>タグなどを埋め込み、この中にプログラムを記述します。

これは、サーバーサイドで保持している変数の値を併用してHTMLを記述するときに、書きやすさ・読みやすさの点で非常に強力です。

例えばサーバーサイドのみでHTML文書を書く場合、次のようなソースコードになります。

app.js
const express = require("express");
const app = express();

app.get("/", (req, res) => {
  const text = "Hello World";
  let data = "<!DOCTYPE html>\r\n";
  data += "<html>\r\n";
  data += "  <head>\r\n";
  data += "    <meta charset='UTF-8'>\r\n";
  data += "    <title>hoge</title>\r\n";
  data += "  </head>\r\n";
  data += "  <body>\r\n";
  data += "<p>";
  data += text
  data += "</p>\r\n";
  data += "  </body>\r\n";
  data += "</html>";
  res.send(data);
});
app.listen(3000);

一方で、テンプレートエンジンを併用した場合は、次のようになります。
クォーテーションや改行を意味する\r\nなどが消え、読み書きしやすくなっているのが分かります。

app.js
const express = require("express");
const app = express();
app.set("view engine", "ejs");

app.get("/", (req, res) => {
  const text = "Hello World";
  res.render("index", {text});
});
app.listen(3000);
index.ejs
<!DOCTYPE html>
<html>
  <head>
    <meta charset='UTF-8'>
    <title>hoge</title>
  </head>
  <body>
    <p><%= text %></p>
  </body>
</html>

実行の準備

さて、まずは環境の構築を行います。
Node.js, MariaDB(MySQL)はインストールされているものとします。

サーバーサイドの準備

以下のコマンドを順に実行して、フレームワークやミドルウェアを導入します。

  • $ npm init
  • $ npm install express --save,
  • $ npm install mysql
  • $ npm install ejs -- save

MariaDB(MySQL)の準備

以下のSQLを順に実行します。
この操作により、Webサイトの名前・URLに関するテーブルを作成し、データの追加も行います。

  • create database website
  • create table website(name varchar(255), url varchar(255));
  • insert into website(name, url) values ("google", "https://www.google.com/"), ("amazon", "https://www.amazon.co.jp/"), ("apple", "https://www.apple.com/"), ("facebook", "https://www.facebook.com/");

実装する

次のような順序で、簡単なことから実装していきます。

  1. EJSを使い、Webブラウザ上でHello Worldする
  2. DB接続を行ってデータを取り出し、ターミナル上にデータを出力する
  3. DB接続を行って、EJSファイルを利用してWebブラウザ上にデータを出力する(ここでは一度失敗してみる)
  4. DB接続を行って、EJSファイルを利用してWebブラウザ上にデータを出力する(再チャレンジし、成功する)

1. EJSでHello Worldしてみよう

まずはDBのことは一旦 忘れて、EJSを使ってHello Worldをしてみます。

下記ソースコードを保存後、ターミナル上で$ node app.jsと入力し、
Webブラウザでhttp://localhost:3000/にアクセスします。

次の画像のように表示されたら成功です。
ちなみに、
app.jsのソースコード内のapp.get()の第一引数はリクエストURL、
第二引数はリクエストが送られたときに実行されるコールバック関数を指します。

この処理を口語的に説明するなら、
http://localhost:3000/が呼ばれたら次のコールバック関数を実行してね!
そしてそのコールバック関数には、index.ejsを表示して!っていう命令も含まれてるよ!
といったところでしょうか。

image.png

実行するソースコード

app.js
const express = require("express");
const app = express();
app.set("view engine", "ejs");

app.get("/", (req, res)=>{
    res.render("index.ejs");  // デフォルトでは /viewsからの相対パスで表すので注意
})

app.listen(3000);

views/index.ejs
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>Hello World</h1>
  </body>
</html>

2. DBに接続してみよう

次に、DB内のデータをターミナル上で表示する実装を行います。

app.jsを次のように書き換えます。
なお、mysql.createConnection()の各種ユーザ情報は、必要に応じて書きかえてください。

実行するソースコード

app.js
const express = require("express");
const app = express();
const mysql = require("mysql");
const connection = mysql.createConnection({
    host: "localhost",
    user: "root",
    password: "1234",
    database: "website"
});
app.set("view engine", "ejs");

app.get("/", (req, res)=>{
    const sql = "select * from website";
    connection.query(sql, (err, result, fields)=>{
        if(err)throw err;
        console.log(result);
    })
    res.render("index.ejs");  // デフォルトでは "/views"ディレクトリからの相対パスで表すので注意
})

app.listen(3000);

ターミナル上で$ node app.jsと入力し、Webブラウザでhttp://localhost:3000/にアクセスします。
前回と同様にHello WorldがWebブラウザに表示されており、
更にターミナル上に、次のような表示があれば成功です。

ここではconsole.log(result)の実行による、ターミナルのデータ出力結果から、
変数resultにはDBから取り出したデータが入っていることが確認できます。

$ node app.js
[
  RowDataPacket { name: 'google', url: 'https://www.google.com/' },
  RowDataPacket { name: 'amazon', url: 'https://www.amazon.co.jp/' },
  RowDataPacket { name: 'apple', url: 'https://www.apple.com/' },
  RowDataPacket { name: 'facebook', url: 'https://www.facebook.com/' }
]

3. DB内のデータをWebブラウザに表示してみる

『1.EJSでHello Worldしてみよう』, 『2.DBに接続してみよう』では、
res.render("index.ejs")とレンダリング先を表記し、ルーティングを設定していました。

今回はレンダリング先にデータを渡すために、
app.get()内にレンダリング先だけではなく、DBから取得したデータも記述する必要があります。
そこでres.render()の第二引数に、レンダリング先に送るデータを記述します。

より具体的にはいえば、
『2. DBに接続してみよう』で、変数resultにDBのデータが格納されることが確認できていました。
このresultをres.render()の第二引数に指定します。
従って、ここではres.render("index", { web: result})と記述します。

ところで{ web: result}という記述に、ややこしさを感じるかもしれません。
これはresultからwebへ名前を置換してから、データを送るという処理を含んでいます。

EJSに対して、resultという変数名をそのままに渡してしまうと、
「result?結果?いや何の結果を表す変数なのか、なんのこっちゃわからん」と、
フロントエンドエンジニアが困惑することになってしまいます。

(webという変数名ならば適切なのかという問題はさておき。)

実行するソースコード

DBに保存しているWebサイト名やURLをWebブラウザ上に出力するため、
app.jsindex.ejsを、それぞれ次のように書き換えます。

app.js
const express = require("express");
const app = express();
const mysql = require("mysql");
const connection = mysql.createConnection({
    host: "localhost",
    user: "root",
    password: "1234",
    database: "website"
});
app.set("view engine", "ejs");

app.get("/", (req, res)=>{
    const sql = "select * from website";
    connection.query(sql, (err, result, fields)=>{
        if(err)throw err;
        console.log(result);
        res.render("index", { web: result});
    })
})

app.listen(3000);
/views/index.ejs
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>Hello World</h1>
    <%= web %>
  </body>
</html>

ターミナルにnode app.jsを入力し、Webブラウザでhttp://localhost:3000/にアクセスします。
次の画像のような、Hello WorldとObjectという文字の羅列が確認できるでしょうか?
半分だけ成功です!

image.png

本来であればGoogleAppleといったWebサイト名や、
https://www.google.com/のようなURLがほしかったところですが、
DBから何らかのデータを取り出すことには、ひとまず成功したのではないでしょうか。
[]で囲まれたよくわからないものは4つで、DBに登録したレコードもちょうど4つでしたしね。

次の項で、この問題を解決します。

4. DB内のデータをWebブラウザに表示してみる(再挑戦)

前項ではDBから、どうやら何らかのデータを取り出すことには成功しましたが、
Webサイトの名前やURLを取得することはできませんでした。

この原因について考えます。

http://localhost:3000/にアクセスしたとき、
console.log(result)の実行によって、ターミナルに何か表示されたことは覚えているでしょうか?

それは、次のような内容でした。

$ node app.js
[
  RowDataPacket { name: 'google', url: 'https://www.google.com/' },
  RowDataPacket { name: 'amazon', url: 'https://www.amazon.co.jp/' },
  RowDataPacket { name: 'apple', url: 'https://www.apple.com/' },
  RowDataPacket { name: 'facebook', url: 'https://www.facebook.com/' }
]

一見するとオブジェクトですが、
出力されたデータは[]で囲まれているため、これはオブジェクトたちを格納している『配列』です

従って、例えばgoogleを取得する場合はweb[0]["name"]と記述します。

実行するソースコード

例として、googlehttps://www.google.com/をWebブラウザ上に表示してみます。
次のようにindex.ejsを書き換え、再度 $ node app.jsで実行します。
下記画像のように、Webサイト名とURLが表示されたら、成功です。

/views/index.ejs
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>Hello World</h1>
    <%= web[0]["name"] %>
    <br>
    <%= web[0]["url"] %>
  </body>
</html>

image.png

この他にも、
for文を利用するなどして、一度に複数のデータを出力すること、あるいはSQLを変更してデータの更新・追加・削除することも可能です。

おわりに

プログラミングを本格的に始めて1年も満たない未熟者の言葉ではありますが、
プログラミング言語の文法を修めるだけでは、Webのシステム開発は正直 不可能です。

私はJavaScriptの文法を学習した後、サーバーサイド言語としてのJavaScript(Node.js)に入門したのですが、
すぐにHTTPリクエスト、ルーティングなどといったWeb特有の専門用語に悩まされました。

Webアプリケーションのサーバーサイドへ入門する前に、
『この一冊で全部わかるWeb技術の基本』, 『Webを支える技術』, 『Web技術速習テキスト』といったWeb周りの情報に触れておくことを、強くおすすめします。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Heroku MySQLにクライアントから接続したい

やりたいこと

HerokuのアプリにアタッチしているMySQLへ、MySQL Workbenchなどのクライアントから接続したい

方法

情報を取得する

アプリ名を取得

herokuにデプロイしているアプリケーションの名前を取得します。
この場合はhogehogeというアプリをデプロイしていることとします。
herokuのアプリ名は、ど忘れしてたり、被らないように特殊にしている場合があるのでcliで取得してコピーしましょう。

$ heroku list
hogehoge
fugafuga

アプリの情報を取得

アプリケーションhogehogeの情報を取得します。
アプリケーションに設定されている環境変数が出力されます。
Heroku上にあるアプリケーションにMySQLをアタッチしている多くの場合において、DATABASE_URLは以下のようになっていると思います。

$ heroku config -a hogehoge
=== hogehoge Config Vars
CLEARDB_DATABASE_URL: mysql://fizz:buzz@foo.cleardb.com/heroku_barbarbar?reconnect=true
DATABASE_URL: mysql://fizz:buzz@foo.cleardb.com/heroku_barbarbar?reconnect=true
以下略

MySQLの接続情報を抜粋する

環境変数の値から接続情報のすべてを読み取ることができます。

// 元が以下だとしたら
mysql://fizz:buzz@foo.cleardb.com/heroku_barbarbar?reconnect=true

// このように読み替える
mysql://username:password@host/schema?reconnect=true

// つまり以下のようになる
MySQLホスト
=> foo.cleardb.com

DB Schema
=> heroku_barbarbar

Username
=> fizz

Password
=> buzz

以上になります。
あとは使っているクライアントに情報を入れて接続してあげるだけです。

最後に

HerokuってデフォルトのデータベースがPostgreSQLなんですが、
MySQLに変えることもできます。
僕の場合には仕事、プライベート、開発環境、本番環境問わず、MySQLを使うことが多いため、PostgresからMySQLへ変えてみました。

変え方については検索すればいくらでもヒットするのでそちらを。
ちなみにクライアントからアクセスして使ってみた感じだと速度が遅めです。まぁ無料なのでそこは仕方ないですね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む