msksgm’s blog

msksgm’s blog

Webエンジニアです.日々の勉強,読書,映画観賞,美術観賞の記録を載せます.

docker-composeでpostgresqlが起動時に"PostgreSQL Database directory appears to contain a database; Skipping initialization"

概要

realworld の laravel バージョン laravel-realword-example-app を一度起動した後に再起動しようとしたときに、以下のようなエラーが発生しました。

解決策についてメモします。

github.com

pgsql_1         |
pgsql_1         | PostgreSQL Database directory appears to contain a database; Skipping initialization
pgsql_1         |
pgsql_1         | 2021-10-09 22:42:10.252 UTC [1] FATAL:  database files are incompatible with server
pgsql_1         | 2021-10-09 22:42:10.252 UTC [1] DETAIL:  The data directory was initialized by PostgreSQL version 13, which is not compatible with this version 14.0.

エラー全文

Creating laravel-realworld-example-app_pgsql_1 ... done
Creating laravel-realworld-example-app_laravel.test_1 ... done
Attaching to laravel-realworld-example-app_pgsql_1, laravel-realworld-example-app_laravel.test_1
pgsql_1         |
pgsql_1         | PostgreSQL Database directory appears to contain a database; Skipping initialization
pgsql_1         |
pgsql_1         | 2021-10-09 22:42:10.252 UTC [1] FATAL:  database files are incompatible with server
pgsql_1         | 2021-10-09 22:42:10.252 UTC [1] DETAIL:  The data directory was initialized by PostgreSQL version 13, which is not compatible with this version 14.0.
laravel-realworld-example-app_pgsql_1 exited with code 1
laravel.test_1  | 2021-10-09 22:42:13,292 INFO Set uid to user 0 succeeded
laravel.test_1  | 2021-10-09 22:42:13,295 INFO supervisord started with pid 16
laravel.test_1  | 2021-10-09 22:42:14,300 INFO spawned: 'php' with pid 17
laravel.test_1  | 2021-10-09 22:42:15,305 INFO success: php entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
laravel.test_1  | Starting Laravel development server: http://0.0.0.0:80
laravel.test_1  | [Sat Oct  9 22:42:17 2021] PHP 8.0.11 Development Server (http://0.0.0.0:80) started

解決方法

docker volumeを削除する必要があるみたいでした。

> docker volume rm $(docker volume ls -qf dangling=true)
laravel-realworld-database

1分で話せ 世界のトップが絶賛した大事なことだけシンプルに伝える技術

「1分で話せ 世界のトップが絶賛した大事なことだけシンプルに伝える技術」[伊藤 羊一 (著) , 2018]を読みました。

感想について記述していきます。

感想

会社の人に進められてので読みました。

感想は、読みやすく良いことは書いてある(かつ、不自然なことは書いていない)けど、目新しいことは書いていないといった印象です。

Z ホールディングスやヤフーなどで、次世代リーダー開発(?)をおこなっている伊藤 洋一さんの本です。 新卒の頃は、プレゼンが苦手だった伊藤さんが、「ソフトバンクアカデミア」の募集で孫正義さんの前で発表し、合格した経験から、伝えるテクニックについてのノウハウが書かれた本です。

正直、内容はあまり新しいことを書いていませんでした。 要約すると、結論、根拠、具体例で簡潔に話し、加えて相手に具体的なイメージを持たせることで行動を促す、という感じです。 「1分」というキーワードは、ほとんどのプレゼンは概要を1分で述べられるし、長々と喋っていても相手は聞いていないから短く伝えろ、というだけでした。 また、「世界のトップが絶賛した」も孫さん以外のことは書かれていなかった気がするので、過剰表現だと思います。 特に研究に基づいた科学的な根拠もなく、具体例も著者のポジショントークしかないので、この本を読んで納得するかと言われたら微妙だと思います。 最後の章である実践編は、受け答えの方法などを書いてあって、少し参考になりましたが、他の本以上のことは書いていないと思います。

発表方法自体は間違ったことを書いていないと思うので「簡潔な発表方法を再認識したい」という人や、最初の方を読んで目新しさを感じたなら読んでみるといいと思います。

phpenvにOracleのoci8とPDO_CLIをインストールする

概要

phpenv に oi8 と PDO_CLI をインストールする機会があったので、メモ感覚で記事を書きます。

インストール方法

Oracle の環境構築

Oracle Instant Client をインストール

Oracle のサイト(url)から、以下をダウンロードします。

  • instantclient-basic-macos.x64-12.2.0.1.0-2.zip
  • instantclient-sqlplus-macos.x64-12.2.0.1.0-2.zip
  • instantclient-tools-macos.x64-12.2.0.1.0-2.zip
  • instantclient-sdk-macos.x64-12.2.0.1.0-2.zip

パッケージの展開

パッケージを展開して、Oracle の実行環境を作ります

cd ~/Downloads
sudo mkdir /usr/local/instantclient/
unzip instantclient-basic-macos.x64-12.2.0.1.0-2.zip
unzip instantclient-sqlplus-macos.x64-12.2.0.1.0-2.zip
unzip instantclient-tools-macos.x64-12.2.0.1.0-2.zip
unzip instantclient-sdk-macos.x64-12.2.0.1.0-2.zip
sudo mv instantclient_12_2 /usr/local/instantclient/12.2.0.1.0
echo 'export ORACLE_HOME="/usr/local/instantclient/12.2.0.1.0"' >> ~/.zshrc
echo 'export TNS_ADMIN="$ORACLE_HOME"' >> ~/.zshrc
exec $SEHLL -l

phpenv で php をインストール

phpenv で php(7.3.29)をインストールします。

インストールする前に oci8 と pdo-oci のパスを環境変数で与えます。

必要なパッケージは以下の記事を参照してください

msksgm.hatenablog.com

export PHP_BUILD_CONFIGURE_OPTS="\
  --disable-fpm \
  --disable-phpdbg \
  --enable-debug \
  --with-bz2=$(brew --prefix bzip2) \
  --with-curl=$(brew --prefix curl) \
  --with-gettext=$(brew --prefix gettext) \
  --with-gmp=$(brew --prefix gmp) \
  --with-iconv=$(brew --prefix libiconv) \
  --with-icu-dir=$(brew --prefix icu4c) \
  --with-jpeg-dir=$(brew --prefix jpeg) \
  --with-libedit=$(brew --prefix libedit) \
  --with-libxml-dir=$(brew --prefix libxml2) \
  --with-libzip=$(brew --prefix libzip)
  --with-mcrypt=$(brew --prefix libmcrypt) \
  --with-png-dir=$(brew --prefix libpng) \
  --with-readline=$(brew --prefix readline) \
  --with-tidy=$(brew --prefix tidy-html5) \
  --with-xsl=$(brew --prefix libxslt) \
  --with-zlib=$(brew --prefix zlib) \
  --with-oci8=shared,instantclient,/usr/local/instantclient/12.2.0.1.0 \
  --with-pdo-oci=shared,instantclient,/usr/local/instantclient/12.2.0.1.0 \
  --with-kerberos"

環境変数の宣言が終わったら、php をインストールします。

エラーなくビルドができたら完了です。

phpenv install 7.3.29

「イノベーションのジレンマ増補改訂版 (Harvard Business School Press)」 感想

イノベーションのジレンマ増補改訂版 (Harvard Business School Press)」[ クレイトン・クリステンセン (著), 玉田 俊平太 (監修), 伊豆原 弓 (翻訳), 2001]を読みました。

感想について記述していきます。

感想

会社の方に進められていたのと、「リーン・スタートアップ」で紹介されていたので読みました。

なぜ、市場をリードしている企業が新興企業に追い抜かれるのかについて解説するビジネス書です。 様々な企業のパターンを踏まえて解説をします。 改訂版が 2001 年ということもあり、解説の例が 1980 年代から 1990 年代のディスクドライブメーカーや掘削機メーカーなどと古いです。 そのため、知らない企業や時代背景などが前提となっているため少し読みづらいです。

破壊的イノベーションの原則は、次の通りです。

  • 原則1:企業は顧客と投資家に資源を依存している
  • 原則2:小規模な市場では大企業の成長ニーズを解決できない
  • 原則3:存在しない市場は分析できない
  • 原則4:組織の能力は無能力の決定的要因になる
  • 原則5:技術の供給は市場の需要と等しいとは限らない

大企業は、先端技術の研究をおこたって衰退するのではなく、むしろ既存の顧客のニーズに答えることで、利益を追求しようとした結果だということがこの本で繰り返し書かれていることです。
大企業には、持続的イノベーションに利益をうける顧客と投資家がいます。それらにニーズを無視した製品をだすことはできません(原則1)。 小規模な市場に売り込もうとしても、既存の製品と比較して利益が低いため、社員と投資家に対して参入することを説得できません(原則2)。 大企業の優秀な経営者たちは、既存の製品の売り上げを成長させることに長けています。しかし、それは既存の市場の話です。そもそもあるかどうかわからない市場に対して分析をすることはできないし、したとしてもだいたい間違っています(原則3)。 組織のできること、できないことは、資源、プロセス、価値基準の3つです。これらを適切に見極めることでできないことを判断します(原則4)。 ある性能で非常に優れた製品を作ったところで、市場の顧客たちが既存の製品に十分に満足していれば、興味をもたず、他の価値基準を探しています(原則5)。 このようにして、大企業はイノベーションのジレンマに陥ってしまいます。

対して、破壊的イノベーションでは、顧客と投資家を持たないため自由に作れ(原則1)、小規模な市場を見つける or 存在しない市場を作る(原則2、原則3)、資源-プロセス-価値基準が破壊的イノベーションをベースにしているから実現可能である(原則4)、小さく始めることとから市場の供給にマッチし、いつしか業界に求める需要になっていく(原則5)のため、成功する。 このようにして、破壊的イノベーションは市場に変化をもたらします。

イノベーションのジレンマを解決する手段は具体的にはありませんが、陥らないようにするため、社内で組織をわけたり、思いも寄らない市場を見つけたりと、対策についてもふれらています。

思いもよらなかった、大企業が衰退していく理由、破壊的イノベーションが成功していく過程などが書いてあるため、興味深い本でした。 ただ、出版年が古いため、昨今の IT 企業やテスラなどのイノベーターたちにこれらの理論をどのようにして解決しているのか、それとも苦しんでいるのかが気になりました。 また、日本語訳の仕方も一つの原則に対して具体例が長すぎるため、少し読み辛かったです(出典や数字の比較が曖昧なビジネス書よりは信憑性がありますが)。

まとめると、2001 年時点で大企業がなぜ衰退するのかまとめた本になります。理由付けがとても具体的で説得力があります。 ただ、例が古すぎて若干読みづらいのと昨今の企業事情については解説できないのが気がかりでした。 他の書籍に紹介される名著なので、紹介元の本が好きだったり、企業について知りたい人にはおすすめです。

docker composeの network で起動順序を設定するシェルスクリプト

概要

docker compose で DB サーバーとバックエンドサーバーを同時に起動すると、DB サーバーが見つからないというエラーが発生してしまいます。docker compose のdepends onであるコンテナの起動する順番を制御できますが、起動完了までは待ってくれません

そこで、docker compose の公式リファレンスにもあるように、起動順序を制御するスクリプトを作成しました。

解決策

起動順序を制御するスクリプト、docker-compose.yml と wait-for-db-contaner について説明していきます。 docker compose upを実行すると、backend-container の内部の処理は db-container の起動が終わるまで待つようになります。

docker-compose.yml

今回使用する docker-compose.yml は以下のようになります。 node.js で作られたバックエンドサーバーである backend-container と、MySQL で作られた DB サーバーの db-container という2つのコンテナを作成します。

いろいろ書いてありますが、重要なのは、db コンテナがあるのと、backend コンテナが./.envを読み込んでおり、実行時のコマンドは["./wait-for-db-container.sh", "yarn", "start"]であるということです。

version: "3.5"
services:
  backend:
    build:
      context: "./"
      dockerfile: "Dockerfile"
    container_name: backend-container
    restart: always
    tty: true
    networks:
      - app-net
    expose:
      - "4000"
    ports:
      - "4000:4000"
    env_file:
      - "./.env"
    depends_on:
      - "db"
    command: ["./wait-for-db-container.sh", "yarn", "start"]
  db:
    image: mysql:5.7.34
    container_name: db-container
    environment:
      MYSQL_DATABASE: "typeorm_db"
      MYSQL_ROOT_PASSWORD: "password"
      TZ: "Asia/Tokyo"
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    expose:
      - "3306"
    ports:
      - "3306:3306"
    volumes:
      - ./initdb.d:/docker-entrypoint-initdb.d
    restart: "always"
    networks:
      - app-net
networks:
  app-net:
    driver: bridge

また、db_container のenv_file で読み込んでいる .env ファイルの中身は以下のようになっています。

PORT=4000

# DB
DB_HOST=db-container
DB_PORT=3306
DB_USERNAME=root
DB_PASSWORD=password
DB_DATABASE=typeorm_db

wait-for-db-cotainer.sh

docker compose upでコンテナを起動したとき、backend-container は DB サーバーの起動を待つシェルスクリプトwait-for-db-container.sh)が実行されます。

mysql コマンドから DB サーバーでexitを実行するコマンドを送ります。 環境変数は .env ファイルから読み込まれています。 これは、エラーでない結果が返ってくるまで、until文が実行を続けます。

エラーでない正常終了を取得したら、until文が終了し、DB が起動したことを伝えます。 この後、wait-for-db-container.shは実行時の残りの引数を実行します。docker-compose.yml でyarn startを与えているため、バックエンドの node.js アプリが起動します。

#!/bin/bash

set -e
cmd="$@"

until mysql -u $DB_USERNAME --port $DB_PORT -h $DB_HOST -p$DB_PASSWORD -D $DB_DATABASE -e 'exit' ; do
  2>&1 echo "$DB_HOST is unavailable - sleeping"
  sleep 10
done

>&2 echo "$DB_HOST is up"
exec $cmd

参考

docs.docker.jp

qiita.com

qiita.com