20200315のMySQLに関する記事は7件です。

ローカル環境へのWordPressインストール方法

はじめに

ここでは、MAMPを使ってローカル環境にWordPressをインストールする方法について解説します。
Windows環境を想定しています。

WordPress用データベースの作成

まず、WordPress用に、MySQLデータベースを作成します。
データベース名はWordPressインストール時に入力しますので、WordPress用のデータベースであることが分かりやすい名前にしておくと良いです。

WordPressのインストール

WordPress公式ページにアクセスし、「Wordpressを入手」をクリックします。

WP-top.PNG

すると、ダウンロードページに移ります。
ここで、WordPress X.X.Xをダウンロードをクリックすると、zipファイルがダウンロードされます。

WP-download.PNG

zipファイルを展開し、MAMPディレクトリのhtdocsディレクトリ下にコピーします(デフォルトの設定の場合)。
そして、「localhost:80/wordpress」にアクセスします(Macの場合はlocalhost:8888)。
すると、以下のような画面が出てくるので、「さあ始めましょう!」をクリックします。

WP-setup.PNG

すると、データベースにアクセスするための情報の入力を求められるので、上で作成したデータベース名などを入力します。

WP-detail.PNG

「インストール実行」をクリックすると、WordPressがインストールされます。

WP-installed.PNG

その後、管理画面にログインするためのユーザー名やパスワードを作成すると、ローカル環境でWordPressを利用できるようになります。

まとめ

ここでは、ローカル環境にWordPressをインストールする方法について解説しました。
WordPressはレンタルサーバーにインストールすることが多いと思いますが、ローカル環境にもインストールしておくと、公開前のサイトの記事の下書きをストックしておいたりなどの使い方ができます。

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

【Laravel】 外部制約キーを migration で設定しようとしたらエラー

何が起きたか

hoge テーブルに users テーブルのid で外部制約キーを設定しようと migrate 実行時にエラーが

結論

bigIntegerで制約を付けたいカラムにを定義しないと、 migrationファイル作成時に記述されている $table->id() と型が異なってしまう

知っていればつまづくポイントにもならないと思いますが、自分の備忘録として・・・

エラーパターン

migration

// users テーブル

public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->string('login_id');
        $table->string('password');
        $table->timestamps();
    });
}
// hoge テーブル

public function up()
{
    Schema::create('hoge', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->integer('user_id')->unsigned();
        $table->timestamps();
        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
    });
}

エラー内容

エラーを見ると
Cannot add foreign key constraint

...エラーが起きたのどこだろ

MySqlの場合下記実行でエラー内容の詳細が見れる。

SHOW ENGINE INNODB STATUS;

status カラムの LATEST FOREIGN KEY ERROR とある部分を見ると

Cannot find an index in the referenced table where the
referenced columns appear as the first columns, or column types
in the table and the referenced table do not match for constraint.

エラーに従って usersidhogeuser_id をチェックすると
users.idBIGINT
hoge.user_idINT

型が違った

修正内容

hoge テーブルの user_id 定義を変更してやればOK

// hoge テーブル 修正後

public function up()
{
    Schema::create('hoge', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->bigInteger('user_id')->unsigned();
        $table->timestamps();
        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
    });
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[db]skeemaというMySQL系データベースのDDL管理ツールを使ってみた

Go言語でDBのスキーマをうまく管理してくれるツール無いの?というところで試したツールの一つ。
skeema/skeema: Schema management CLI for MySQL
ザックリ言うと、RailsでいうActiveRecord::Schemaみたいなスキーマダンプを作ってくれるやつ。

環境

  • macOS Catalina
  • go version 1.13.4

記事執筆時点で対応しているデータベース

MySQL系のプロダクトの模様。

  • MySQL 5.5, 5.6, 5.7, 8.0
  • Percona Server 5.5, 5.6, 5.7, 8.0
  • MariaDB 10.1, 10.2, 10.3, 10.4

準備

go get -u github.com/skeema/skeema

使い方

現在のスキーマをダンプ

下記のコマンドを適宜編集して実行する。

skeema init -h my.db.hostname -u root -p -d schemas --schema dbname

するとschemasディレクトリ以下にテーブルごとにDDLがファイルが出力される。
-dで指定したディレクトリにダンプされる。
--schemaオプション無しの場合は、ユーザーが作ったすべてのデータベース毎のディレクトリが作られ、その中にそれぞれのデータベースにあるテーブル定義が出力される。
--schemaありの場合は、指定ディレクトリの直下にファイルが出力される。
skeema init --helpで詳細なオプションを確認できる。
この時の接続情報は.skeemaファイルに記録されている。

スキーマを変更して適用

例えば以下のように変更してみる。

CREATE TABLE `applications` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `ios_bundle_name` varchar(255) DEFAULT NULL,
  `android_bundle_name` varchar(255) DEFAULT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  `deleted_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

CREATE TABLE `applications` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(256) NOT NULL,
  `ios_bundle_name` varchar(255) DEFAULT '',
  `android_bundle_name` varchar(255) DEFAULT NULL,
  `created_at` datetime,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

これを適用してみる。

まず差分をチェックする。
skeema diffで実際にどのようなSQL文が発行されるかを確認できる。
今回は列の削除が含まれるので、--allow-unsafeオプションが必要。

$ skeema diff -p --allow-unsafe
:
-- instance: localhost:/tmp/mysql.sock
USE `testdb`;
ALTER TABLE `applications` DROP COLUMN `deleted_at`, MODIFY COLUMN `name` varchar(256) NOT NULL, MODIFY COLUMN `ios_bundle_name` varchar(255) DEFAULT '', MODIFY COLUMN `created_at` datetime DEFAULT NULL, ADD UNIQUE KEY `name` (`name`);

次に実際に適用してみる。

$ skeema push -p --allow-unsafe
:
-- instance: localhost:/tmp/mysql.sock
USE `testdb`;
ALTER TABLE `applications` DROP COLUMN `deleted_at`, MODIFY COLUMN `name` varchar(256) NOT NULL, MODIFY COLUMN `ios_bundle_name` varchar(255) DEFAULT '', MODIFY COLUMN `created_at` datetime DEFAULT NULL, ADD UNIQUE KEY `name` (`name`);
2020-03-15 14:44:46 [INFO]  localhost:/tmp/mysql.sock testdb: push complete

Sequel Proなどで軽く確認すると、適用されている事が分かる。

ここでは記載していないが、テーブルの追加や削除にも対応している。
削除時には--allow-unsafeが必要。

スキーマの差分を反映する

直接本番で作業した、開発環境でテーブルをGUIで変更したなどの理由で差分をDDLに反映させたい場合などがあるだろう。
そういう場合にはskeema pullを利用できる。

$ skeema pull -p               
Enter password: 
2020-03-15 14:59:13 [INFO]  Updating /path/to/schemas to reflect localhost:/tmp/mysql.sock testdb
2020-03-15 14:59:13 [INFO]  Wrote /path/to/schemas/applications.sql (425 bytes)

フォーマット

skeema format -pでSQL文の整形ができる。

lint

skeema lint -pでlintできる。こんな感じ。

2020-03-15 14:40:52 [INFO]  Linting /path/to/schemas
2020-03-15 14:40:53 [WARN]  /path/to/schemas/applications.sql:2: Column id of table applications is an auto_increment column
                            using data type int, which is not configured to be permitted. The following data types are listed in option
                            allow-auto-inc: int unsigned, bigint unsigned.
                            In general, auto_increment columns should be unsigned, since behavior of auto_increment is undefined with negative
                            numbers.
2020-03-15 14:40:53 [WARN]  Found 1 warnings

GitHubにインストールして使えるCIサービスもある。現在ベータ版で無料。

環境を分ける

最初に生成されるのはproductionの設定だが、developstagingなど環境を追加する事も可能。
残念な事に、データベース名(scheme)は共通となっており、本番と合わせる必要がある。

$ skeema add-environment development -h localhost -u root -p
2020-03-15 15:01:46 [INFO]  Added environment [development] to /path/to/schemas/.skeema

環境を指定する際は一番最後に付ける。
skeema pull -p developmentなど。
お察しの通り、何も指定しない場合はproductionになる。
どちらかと言うと本番の時に指定させて欲しいところだが…

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

[db]MySQL系データベースのDDL管理ツールskeemaを使ってみた

Go言語でDBのスキーマをうまく管理してくれるツール無いの?というところで試したツールの一つ。
skeema/skeema: Schema management CLI for MySQL
ザックリ言うと、RailsでいうActiveRecord::Schemaみたいなスキーマダンプを作ってくれるやつ。

環境

  • macOS Catalina
  • go version 1.13.4

記事執筆時点で対応しているデータベース

MySQL系のプロダクトの模様。

  • MySQL 5.5, 5.6, 5.7, 8.0
  • Percona Server 5.5, 5.6, 5.7, 8.0
  • MariaDB 10.1, 10.2, 10.3, 10.4

準備

go get -u github.com/skeema/skeema

使い方

現在のスキーマをダンプ

下記のコマンドを適宜編集して実行する。

skeema init -h my.db.hostname -u root -p -d schemas --schema dbname

するとschemasディレクトリ以下にテーブルごとにDDLがファイルが出力される。
-dで指定したディレクトリにダンプされる。
--schemaオプション無しの場合は、ユーザーが作ったすべてのデータベース毎のディレクトリが作られ、その中にそれぞれのデータベースにあるテーブル定義が出力される。
--schemaありの場合は、指定ディレクトリの直下にファイルが出力される。
skeema init --helpで詳細なオプションを確認できる。
この時の接続情報は.skeemaファイルに記録されている。

スキーマを変更して適用

例えば以下のように変更してみる。

CREATE TABLE `applications` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `ios_bundle_name` varchar(255) DEFAULT NULL,
  `android_bundle_name` varchar(255) DEFAULT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  `deleted_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

CREATE TABLE `applications` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(256) NOT NULL,
  `ios_bundle_name` varchar(255) DEFAULT '',
  `android_bundle_name` varchar(255) DEFAULT NULL,
  `created_at` datetime,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

これを適用してみる。

まず差分をチェックする。
skeema diffで実際にどのようなSQL文が発行されるかを確認できる。
今回は列の削除が含まれるので、--allow-unsafeオプションが必要。

$ skeema diff -p --allow-unsafe
:
-- instance: localhost:/tmp/mysql.sock
USE `testdb`;
ALTER TABLE `applications` DROP COLUMN `deleted_at`, MODIFY COLUMN `name` varchar(256) NOT NULL, MODIFY COLUMN `ios_bundle_name` varchar(255) DEFAULT '', MODIFY COLUMN `created_at` datetime DEFAULT NULL, ADD UNIQUE KEY `name` (`name`);

次に実際に適用してみる。

$ skeema push -p --allow-unsafe
:
-- instance: localhost:/tmp/mysql.sock
USE `testdb`;
ALTER TABLE `applications` DROP COLUMN `deleted_at`, MODIFY COLUMN `name` varchar(256) NOT NULL, MODIFY COLUMN `ios_bundle_name` varchar(255) DEFAULT '', MODIFY COLUMN `created_at` datetime DEFAULT NULL, ADD UNIQUE KEY `name` (`name`);
2020-03-15 14:44:46 [INFO]  localhost:/tmp/mysql.sock testdb: push complete

Sequel Proなどで軽く確認すると、適用されている事が分かる。

ここでは記載していないが、テーブルの追加や削除にも対応している。
削除時には--allow-unsafeが必要。

スキーマの差分を反映する

直接本番で作業した、開発環境でテーブルをGUIで変更したなどの理由で差分をDDLに反映させたい場合などがあるだろう。
そういう場合にはskeema pullを利用できる。

$ skeema pull -p               
Enter password: 
2020-03-15 14:59:13 [INFO]  Updating /path/to/schemas to reflect localhost:/tmp/mysql.sock testdb
2020-03-15 14:59:13 [INFO]  Wrote /path/to/schemas/applications.sql (425 bytes)

フォーマット

skeema format -pでSQL文の整形ができる。

lint

skeema lint -pでlintできる。こんな感じ。

2020-03-15 14:40:52 [INFO]  Linting /path/to/schemas
2020-03-15 14:40:53 [WARN]  /path/to/schemas/applications.sql:2: Column id of table applications is an auto_increment column
                            using data type int, which is not configured to be permitted. The following data types are listed in option
                            allow-auto-inc: int unsigned, bigint unsigned.
                            In general, auto_increment columns should be unsigned, since behavior of auto_increment is undefined with negative
                            numbers.
2020-03-15 14:40:53 [WARN]  Found 1 warnings

GitHubにインストールして使えるCIサービスもある。現在ベータ版で無料。

環境を分ける

最初に生成されるのはproductionの設定だが、developstagingなど環境を追加する事も可能。
残念な事に、データベース名(scheme)は共通となっており、本番と合わせる必要がある。

$ skeema add-environment development -h localhost -u root -p
2020-03-15 15:01:46 [INFO]  Added environment [development] to /path/to/schemas/.skeema

環境を指定する際は一番最後に付ける。
skeema pull -p developmentなど。
お察しの通り、何も指定しない場合はproductionになる。
どちらかと言うと本番の時に指定させて欲しいところだが…

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

MySQLでdatetime型の演算をする

以下のようなテーブルがある.

MariaDB [staging]> desc guests;
+---------------+----------------------+------+-----+---------+----------------+
| Field         | Type                 | Null | Key | Default | Extra          |
+---------------+----------------------+------+-----+---------+----------------+
| id            | smallint(5) unsigned | NO   | PRI | NULL    | auto_increment |
| department_id | smallint(5) unsigned | YES  | MUL | NULL    |                |
| user_id       | varchar(10)          | YES  |     | NULL    |                |
| comment       | varchar(255)         | YES  |     | NULL    |                |
| entered_at    | datetime             | NO   |     | NULL    |                |
| updated_at    | datetime             | NO   |     | NULL    |                |
| exited_at     | datetime             | YES  |     | NULL    |                |
+---------------+----------------------+------+-----+---------+----------------+
7 rows in set (0.036 sec)

現状では,JSTでdatetime型のカラムに記録されている.

MariaDB [staging]> select * from guests;
+----+---------------+----------+-----------------------------+---------------------+---------------------+---------------------+
| id | department_id | user_id  | comment                     | entered_at          | updated_at          | exited_at           |
+----+---------------+----------+-----------------------------+---------------------+---------------------+---------------------+
|  3 |             1 | C0117123 | これはテストです〜          | 2019-08-08 02:41:20 | 2019-08-08 20:41:20 | 2020-03-02 23:00:09 |

ここでは entered_at カラムの時刻をUTCへ修正する.

UPDATE guests SET entered_at=entered_at - INTERVAL 9 HOUR

修正されたことが確認できる.

MariaDB [staging]> select * from guests;
+----+---------------+----------+-----------------------------+---------------------+---------------------+---------------------+
| id | department_id | user_id  | comment                     | entered_at          | updated_at          | exited_at           |
+----+---------------+----------+-----------------------------+---------------------+---------------------+---------------------+
|  3 |             1 | C0117123 | これはテストです〜          | 2019-08-07 17:41:20 | 2019-08-08 20:41:20 | 2020-03-02 23:00:09 |
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Go】【xorm/reverse】MySQLのINT UNSIGNEDに対応する!

はいどうも~:clap:

新人のプルリクに、選択肢を2つ与えつつ「自分のチカラで考えてみそ」とレビューしたら、なぜか新米部長から横レスで「じゃあお前が決めろよ、ちなみに選択肢Bは俺的に無しだから」と来て、何が琴線?に触れたのか不明ですがとりまLGTMで済ませた昨今、いかがお過ごしでしょうか:sunglasses::v:

今回は、↓でご紹介したxorm/reverseを改造したお話です。

何を変えたの?

MySQL DBリバース

Go言語のstructコード

INT UNSIGNEDカラムが、ただのint型structフィールドになってしまう

uint型になってほしい

改造

変更点

まずは、最新版xorm/reversexorm/xormの帳尻合わせ

xorm/reversexorm/xorm(xorm本体)をインポートしていて大部分依存しているのですが、xorm/xormのバージョンが0.810.82と上がっていたので「どうせなら最新版に合わすか」と軽い気持ちで

go.mod
require (
・
・
・
    xorm.io/xorm latest
)

latestで引っ張りなおしたら、結構影響が…
このver0.01の更新でリファクタリングがあったようです。

ので、まずはxorm/reverseを最新xorm/xormに合わせる修正をします。

※ご注意: giteaリポジトリ上のルートはxormですが、go package名は公式サイトドメインに沿ってxorm.ioになっているようです。

cmd/reverse.go, language/golang.go, language/language.go

Table, Column構造体がパッケージcoreからschemasに移動していたので、

  • import "xorm.io/xorm/schemas" を追加
  • core.Table, core.Columnschemas.Table, schemas.Column に修正

これで、最新版xorm/xormをインポートしたxorm/reverseがビルド可能になりました。

リバースロジックに手を入れ…

そう単純にはいかないようです…

処理を追跡すると、language/golang.gotypestring()で呼ばれているschemas.SQLType2Type()の中で変換が行われているようです。
これってxorm/xorm本体側のfuncですよね…

…分かりました、やりましょう!
xorm/xormも改造しちゃいます!

xorm/xorm最新版をgit clone

早速xorm/xormgit cloneしてきます。
ディレクトリはxorm.io/reverseと同じ階層になるようにします。

$ cd ../
$ git clone https://gitea.com/xorm/xorm.git
$ ls
xorm/ reverse/

手元のxorm/reverseが、同じく手元のxorm/xormを参照するように変更

※Go Modules方式でビルドしている前提です。

reverse/go.modに↓を追記します。

go.mod
replace xorm.io/xorm => ../xorm

これでxorm.io/xormパッケージのライブラリだけ、ネット上に公開されているものではなく手元のディスク内のものを参照するようになります。

今度こそ、リバースロジックに手を入れる!

えっと、目論見を付けたのはschemas.Type2SQLType()でしたね。
このfuncは…xorm/schemas/type.goにありますね。
早速手を入れていきましょう。

type.go
// default sql type change to go types
func SQLType2Type(st SQLType) reflect.Type {
    name := strings.ToUpper(st.Name)
    switch name {
    case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, Serial:
        return reflect.TypeOf(1)
    case BigInt, BigSerial:
        return reflect.TypeOf(int64(1))

ここにcase UInt:を足せばいいのかなと思いますが、きっとそれだけでは済まないですね…
でもこれはこれで必要なので足します。

type.go
func SQLType2Type(st SQLType) reflect.Type {
    name := strings.ToUpper(st.Name)
    switch name {

    case UInt: // ←
        return reflect.TypeOf(uint(1)) // ←

定数宣言部が冒頭にあるのでそれも足します。

type.go
var (

    UInt       = "INT UNSIGNED" // ←

    SqlTypes = map[string]int{

        UInt:       NUMERIC_TYPE, // ←

)

さて、GoLandのデバッグ実行を使ってみましたがINT UNSIGNEDカラムを持つテーブルを食わせてもSQLType2Typeのパラメータst.Nameとして渡ってくる時点でUNSIGNEDが削られてしまっています…

…ここはひとつ、ちゃんとイチから辿ってみますか。

  • reverse/cmd/reverse.go
    • Reverse() >
    • runreverse()>
  • xorm/engine.go
    • DBMetas()>
    • loadTableInfo() >
  • xorm/dialects/dialect.go
    • GetColumns() >
  • xorm/dialects/mysql.go
    • GetColumns()

お、ここにMySQLのカラム宣言部を解析する処理がありました。

mysql.go
func (db *mysql) GetColumns(ctx context.Context, tableName string) ([]string, map[string]*schemas.Column, error) {

        cts := strings.Split(colType, "(")
        colName := cts[0]
        colType = strings.ToUpper(colTypeBase)

ここで、例えばINT(10) UNIQUE UNSIGNED NOT NULLといったカラム宣言からINTを切り出しています。
これだと確かにUNSIGNEDが切り捨てられちゃいますね。
なのでINT(X) ... UNSIGNED ...からINT UNSIGNEDとして拾い上げるよう修正します。

mysql.go
func (db *mysql) GetColumns(ctx context.Context, tableName string) ([]string, map[string]*schemas.Column, error) {

        cts := strings.Split(colType, "(")
        //colName := cts[0]
        var colTypeBase string
        group :=  regexp.MustCompile(`(?i)([a-zA-Z]+).*(\sUNSIGNED?).*`).FindSubmatch([]byte(colType))
        if group == nil {
            colTypeBase = cts[0]
        } else {
            for i, g := range group {
                if i == 0 {
                    continue
                }
                colTypeBase += string(g)
            }
        }
        colType = strings.ToUpper(colTypeBase)

ここ、実はMySQL側のバージョンによって罠がありました。

MySQL5.xだとINT UNSIGNED ...とカラム宣言しても、テーブル作成時、自動的にINT(10) UNSIGNED ...と、(10)が付けられてしまうので↑この修正が必要です。(MySQL8.xだとこの現象は発生しません。)

いずれにしろ、↑のようにしておけば大丈夫です。

実行

ではxorm/reverseを実行してみましょう。

$ cd reverse
$ go run main.go -f example/my-mysql.yml

※設定ファイルmy-mysql.ymlの内容は、前回記事 https://qiita.com/yagrush/items/cc60166d85befbcbf3d6 をご参照下さい。

すると、例えば↓のテーブルが

CREATE TABLE `users` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
);

type User struct {
    Id        uint      
    Name      string    
    CreatedAt *time.Time
}

Id uintになってますね:ok_hand:

おわり

ということで、以下を修正することでINT UNSIGNEDカラムに対応することができました。

  • xorm/reverse

    • cmd/reverse.go
    • language/golang.go
    • language/language.go
  • xorm/xorm

    • schemas/type.go
    • dialects/mysql.go

実際には、この修正でBIGINT UNSIGNEDなどもUNSIGNED付きで拾ってしまうようになるので 併せて修正が必要なのですが、ほぼコピペで済むので。
記事が冗長になってしまうので、ここでは割愛します。

それではまた!

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

golang,docker,mysqlの環境をherokuにデプロイする

はじめに

言語: golang
コンテナ: docker-compose
RDB: mysql
ORM: gorm
マイグレーション: migrate

な環境をherokuにデプロイするまで結構ハマったので残す。

コード

https://github.com/pokotyan/study-slack

実行したherokuのコマンド一覧

$ cd /hoge/huga                    # アプリケーションのコードがあるところに移動
$ heroku container:login           # ログイン
$ heroku create -a app_name        # herokuアプリの作成
$ heroku git:remote -a app_name    # herokuリポジトリをgit登録
$ heroku addons:add cleardb:ignite # mysqlのアドオンを追加
$ heroku config                    # CLEARDB_DATABASE_URLが登録されていることを確認
$ heroku config:set DATABASE_URL="<ユーザー名>:<password>@tcp(<ホスト名>:3306)/<DB名>?parseTime=true" # CLEARDB_DATABASE_URLの値を元にsql.Open()に渡す用の文字列に整形
$ heroku config                    # DATABASE_URLが登録されていることを確認
$ heroku stack:set container       # heroku.ymlを使う時はこれがいるぽい
$ git push heroku master           # リリース

heroku.yml

heroku.ymlを使うとCI/CDみたいなことができる。アプリのルートディレクトリに置いて使う。
buildにはdockerのビルドの指定ができる。
releaseにはリリースする際に挟みたい処理があれば書くことができる。ここではマイグレーションの実行をしている。
runはプロセスタイプ1ごとに実行するコマンドを指定する。

./heroku.yml
build:
  docker:
    web: Dockerfile
    worker:
      dockerfile: Dockerfile
      target: builder 
release:
  image: worker
  command:
    - make up_migrate_prod
run:
  web: /main

Dockerfile

上述のheroku.ymlが参照するDockerfile。アプリのルートディレクトリに置く。
いくつかポイントがある。

./Dockerfile
FROM golang:alpine as builder

RUN apk update \
  && apk add --no-cache git curl make gcc g++ \
  && go get github.com/oxequa/realize

WORKDIR /app
COPY go.mod .
COPY go.sum .

RUN go mod download
COPY . .

RUN GOOS=linux GOARCH=amd64 go build -o /main

FROM alpine:3.9

COPY --from=builder /main .

ENV PORT=${PORT}
ENTRYPOINT ["/main"]

ライブラリのインストール

./Dockerfile
RUN apk update \
  && apk add --no-cache git curl make gcc g++ \
  && go get github.com/oxequa/realize

realizeは開発時のホットリロードのため。
make、gcc、g++はheroku.ymlのreleaseフェーズにてmakeコマンドでマイグレーションを流せるようにするため
curlはherokuのUI上でログを残すため(※)。

※ curlを入れていないとこんな感じで何も表示されない。リリースが途中で死んでもなんで落ちたかが追えなくなるので入れておいた方がいいと思う。ログを出すためにcurlが必要なことは公式にも記載されている。
スクリーンショット 2020-03-15 0.59.01.png

ビルド

builderのイメージはheroku.ymlでイメージのビルドをする際に使ったり、マイグレーションを実行する時のイメージとして利用している。

./Dockerfile
FROM golang:alpine as builder
./heroku.yml
build:
  docker:
    web: Dockerfile
    worker:
      dockerfile: Dockerfile
      target: builder # builderのイメージをbuildする際に使う
release:
  image: worker # 上記のworkerのイメージをreleaseフェーズでも使う
  command:
    - make up_migrate_prod # マイグレーションを流す

アプリの実行

RUN GOOS=linux GOARCH=amd64 go build -o /main でビルドしたファイルを実行する

./Dockerfile
FROM alpine:3.9

COPY --from=builder /main .

ENV PORT=${PORT}
ENTRYPOINT ["/main"]
./heroku.yml
run:
  web: /main

docker-compose.yml

ローカルで開発する時のみに利用するdocker-compose.yml。
realizeを使ってホットリロードするようにしている。
また、mysqlのコンテナが立ち上がる際に docker-entrypoint-initdb.d を利用して CREATE DATABASE をするようにしている。

herokuの本番環境ではdatabaseは heroku addons:add cleardb:ignite で用意されたものを利用する。
そのため、本番環境ではこのdocker-compose.ymlは利用しない。

dockers/docker-compose.yml
version: "3.5"

services:
  mysql:
    container_name: push_study_db
    image: mysql:5.7.22
    volumes:
      - ./mysql/:/docker-entrypoint-initdb.d/
      - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf
    environment:
      - MYSQL_ALLOW_EMPTY_PASSWORD=yes
    ports:
      - 4306:3306
  app:
    build:
      context: ..
      target: builder
    volumes:
      - ../:/app
    command: realize start --server
    environment:
      - API_VERSION=development
    ports:
      - 7777:7777
    depends_on:
      - mysql

起動するポート

herokuはアプリが起動するたびにポートが変わるらしい。$PORTを指定して起動するようにする。

    router.Run(":" + os.Getenv("PORT"))

CLEARDB_DATABASE_URL

mysqlのアドオンを追加するとCLEARDB_DATABASE_URLという環境変数が自動で設定される。
heroku.ymlのreleaseフェーズで流れるようにしたマイグレーションだが、そのコードでは以下のようにしてdbと接続していた。

    dbURL := os.Getenv("CLEARDB_DATABASE_URL")
    db, _ := sql.Open("mysql", dbURL)

リリースを実行すると invalid memory address or nil pointer dereference のエラーが出る。

スクリーンショット_2020-03-15_1_17_03.png

結果として、herokuが自動で作成してくれるCLEARDB_DATABASE_URLの書式をsql.Openが求めている書式に変換する必要があった。こちらの記事を参考にさせていただきました。
冒頭のherokuのコマンド一覧のところでも記載しているが、"<ユーザー名>:<password>@tcp(<ホスト名>:3306)/<DB名>?parseTime=true" の形にしてあげる必要があった。

最後に

herokuのリリース方法、色々ありすぎてまとまった情報を見つけるのが難しい。

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