見出し画像

akippaの開発環境のお話

akippa株式会社でリードエンジニアという肩書きで色々やらせてもらっている村上と申します。

akippaでは絶賛エンジニア募集中なのですが、エンジニアの方が転職される際に気になる事の一つに、開発環境ってどうなってるの?っていうのがあると思います。
今回は、akippaの開発環境について語りたいと思います。

開発環境の構築方法は、以下に挙げる例のようにいくつかやり方があると思います。

  1. ローカルPC(Windows、Mac)のホストOS自体にWebサーバをインストールしてそこで動かす

  2. 各個人用のサブドメインを用意し、クラウド(AWSのEC2等)に建てているWebサーバで動かす

  3. Virtual box + Vagrant使う

  4. Docker使う

私のakippa入社前の経験上では、公私ともに1のやり方が多かったです。
プログラム初心者向けのPHP等の書籍の冒頭に紹介されている環境構築セクションでは大体このやり方を紹介している事が多いのではないでしょうか。
ただ、WindowsやMacにインストールしたApacheやNginxで動かして問題なくとも、本番環境がLinuxだと、開発中に起こらなかった問題が本番で起こる事もあると思います。

入社当時

私がakippaに入社した2016年当時、各個人の開発環境は、2の「各個人用のサブドメインを用意し、クラウド(AWSのEC2等)に建てているWebサーバで動かす」でやっていました。
私は、AWS等のクラウドを利用するというのがakippaで初めてでして、へーこんなやり方でやるんだーと驚きました。
murakami.akippa.comなんてサブドメインが実在していました笑
(今は閉鎖済み!)
ただ、本番に近い環境で動作させる事ができる一方で、新しい方がジョインされる度に、インフラ担当の方がサブドメイン作成からWebサーバに開発者ユーザーアカウント作ったり仮想ホストを構築するという手間が避けられないのと、開発時には、各開発者がソースをそのサーバにどうやってあげるか人によって違ったり(git経由かscpコマンドかFTP系のツール使うか等)とか、ステップ実行とかも簡単にできないので、デバッグ時にはログをいちいち仕込んでログファイル見て…って感じで、日々面倒さを感じてました。

Laravel導入初期(2017年終盤〜)

私が入社して1年が過ぎた2017年終盤あたりに、akippaのフロントサイトや管理サイトを、PHPフレームワークのLaravelを用いて、部分的にリニューアルをしていこうとする動きが始まりました。
そのときに、3の「Virtual box + Vagrant使う」でローカル開発環境を用意する事にしました。
そのときのローカル環境構築の役割を買って出た私ですが、Vagrantで使うboxは、ubuntuのboxを基にして、NginxやPHP等必要なパッケージをインストールして独自のboxを作ってメンバーに配布しておりました。
必要なものが全て入ったboxなので、新しい人が入ってもすぐに使えていいやん!って思ってたのですが、どういうコマンドで何がインストールされたboxなのか作者である私ですらわからなくなってしまった。
お恥ずかしながら、当時の私は「Infrastructure as Code」という考え方を知らなかったんですね。
「Infrastructure as Code」を意識して以降は、一部vagrantのprovisionでインストールする事にしたのですが、新しい人が新しいOSで構築しようとしたときに、構築途中で何やらエラーが出るようになったり…。
また、相変わらずLaravelではない古いフレームワークで動作しているサイトについては、依然クラウド側の個人環境で動作させていました。

という感じで、これからエンジニア採用を張り切っていきましょう!というときに、このままだと新しく入られる方が、入社初日の環境構築で詰まったり、僕がやるインフラ側の設定云々で待たせる事になり、ストレスを掛けてしまう事になる…。
そこで、何年か前からやろうと思ってずるずる伸ばしてしまっていた4の「Docker使う」に舵を切る事にしました。

現在(2022年〜)

Dockerで構築したい環境はこんな環境

Dockerは、簡単な構成のサイトならすぐに構築できますが、akippaの環境をなるべく忠実に再現しようと思うと大変だろうと思っていました。
akippaでは、複数のWebサイトが存在しています。
・ドライバーさんが駐車場の予約等に用いるフロントサイト
・オーナーさんが予約状況の確認等をされるオーナーサイト
・akippaの運用担当が用いる管理サイト
・スマホアプリ用等のAPI
・一部の画像、JS、CSSの静的コンテンツを配置しているサイト
等があり、これらを同一ドメイン、別サブドメインにて運用しております。
また、それぞれ、開発着手時期の違いなどから、使用しているフレームワークやPHPバージョンなども違います。
フロントサイトに至っては、画面ごとに新旧のフレームワークが混在していて、本番環境ではALBのパスルーティングを用いて、特定URLならLaravelが動作しているWebサーバへ、そうじゃないならZend Frameworkが動作しているWebサーバへ、みたいな振り分けをおこなっています。
それぞれのサイトから参照するデータベースは同じです。(本番ではライター、リーダー数台の複数構成ではありますが)
これを一発で再現できるdocker-composeの作成が私に与えられた(与えた)ミッションでした!

docker-compose.yml を見れば全てわかる!?

このページに来られる方は、akippaに興味を持っていただいているエンジニアの方か、もしくはDockerで詰まってググって来られた方になるのでは!?と思いますので、四の五の言わずに、docker-compose.ymlをさらけ出してしまいましょう!笑
もちろん、バージョン等一部ボカしたり、説明に冗長な記述は消してます!
予想通り、akippaの環境の再現はやっぱり大変でした!

version: "3"

services:
  proxy:
    image: jwilder/nginx-proxy:0.10.0
    restart: always
    privileged: true
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - $PWD/certs:/etc/nginx/certs
      - $PWD/proxy/local.akippa.com:/etc/nginx/vhost.d/local.akippa.com
      - /var/run/docker.sock:/tmp/docker.sock:ro
    environment:
      TZ: Asia/Tokyo
    networks:
      akippa-network:
        ipv4_address: 172.30.0.2

  laravel-web:
    image: nginx:x.x.x
    restart: always
    privileged: true
    depends_on:
      - proxy
      - laravel-php
    volumes:
      - $PWD/laravel/default.conf:/etc/nginx/conf.d/default.conf
      - $PWD/../../akippa_laravel:/var/www/html
    environment:
      VIRTUAL_HOST: local-admin2.akippa.com,local-owner.akippa.com,local-api.akippa.com,local-partner.akippa.com,local-laravel.akippa.com
      TZ: Asia/Tokyo
    networks:
      akippa-network:
        ipv4_address: 172.30.0.3

  laravel-php:
    build: $PWD/laravel
    restart: always
    privileged: true
    volumes:
      - $PWD/../../akippa_laravel:/var/www/html
    environment:
      TZ: Asia/Tokyo
    networks:
      akippa-network:
        ipv4_address: 172.30.0.4
    extra_hosts:
      - "local-api.akippa.com:172.30.0.2"
  
  zend-front:
    build: $PWD/zend
    restart: always
    privileged: true
    depends_on:
      - proxy
    working_dir: /var/www/local
    volumes:
      - $PWD/zend/000-default.conf:/etc/apache2/sites-available/000-default.conf
      - $PWD/../../akippa:/var/www/local
    environment:
      VIRTUAL_HOST: local.akippa.com
      TZ: Asia/Tokyo
    networks:
      akippa-network:
        ipv4_address: 172.30.0.5
    extra_hosts:
      - "local-api.akippa.com:172.30.0.2"

  zend-admin:
    build: $PWD/zend
    restart: always
    privileged: true
    depends_on:
      - proxy
    working_dir: /var/www/local
    volumes:
      - $PWD/zend/000-default.conf:/etc/apache2/sites-available/000-default.conf
      - $PWD/../../akippa_admin:/var/www/local
    environment:
      VIRTUAL_HOST: local-admin.akippa.com
      TZ: Asia/Tokyo
    networks:
      akippa-network:
        ipv4_address: 172.30.0.6
    extra_hosts:
      - "local-api.akippa.com:172.30.0.2"

  zend-api:
    build: $PWD/zend
    restart: always
    privileged: true
    depends_on:
      - proxy
    working_dir: /var/www/local
    volumes:
      - $PWD/zend/000-default.conf:/etc/apache2/sites-available/000-default.conf
      - $PWD/../../akippa_api:/var/www/local
    environment:
      VIRTUAL_HOST: local-zend-api.akippa.com
      TZ: Asia/Tokyo
    networks:
      akippa-network:
        ipv4_address: 172.30.0.7

  res:
    build: $PWD/res
    restart: always
    privileged: true
    working_dir: /opt
    volumes:
      - $PWD/../../akippa_res:/opt
    environment:
      VIRTUAL_HOST: local-res.akippa.com
      TZ: Asia/Tokyo
    networks:
      akippa-network:
        ipv4_address: 172.30.0.8

  db:
    image: mysql:x.x
    restart: always
    ports:
      - "13306:3306"
    command:
      - --sql-mode=NO_ENGINE_SUBSTITUTION
      - --ft_min_word_len=2
      - --innodb_ft_min_token_size=2
    volumes:
      - akippa-db-volume:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: xxx
      MYSQL_DATABASE: xxx
      MYSQL_USER: xxx
      MYSQL_PASSWORD: xxx
      TZ: Asia/Tokyo
    networks:
      akippa-network:
        ipv4_address: 172.30.0.9

  unit-test-db:
    image: mysql:x.x
    restart: always
    ports:
      - "13307:3306"
    command:
      - --sql-mode=NO_ENGINE_SUBSTITUTION
      - --ft_min_word_len=2
      - --innodb_ft_min_token_size=2
    volumes:
      - akippa-unit-test-db-volume:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: xxx
      MYSQL_DATABASE: xxx
      MYSQL_USER: xxx
      MYSQL_PASSWORD: xxx
      TZ: Asia/Tokyo
    networks:
      akippa-network:
        ipv4_address: 172.30.0.10

  memcached:
    image: memcached:x.x.x
    restart: always
    networks:
      akippa-network:
        ipv4_address: 172.30.0.11

volumes:
  akippa-db-volume:
  akippa-unit-test-db-volume:

networks:
  akippa-network:
    driver: bridge
    ipam:
     driver: default
     config:
       - subnet: 172.30.0.0/24

どなたに向けて書くかでどこまで細かく説明するか考える必要があるんですが、あまり掘ると書ききれないので、超ざっくりな説明にします!
docker-compose.ymlを見ると、大きくは3つのセクションがあり、上からservices、volumes、networksとあります。
servicesには、必要なdockerコンテナが記述されています。
volumesには、volumeですね。Dockerは、基本的には終了したら全部消えてしまいますが、DBのデータ等、永続化したい場合はvolumeという機能を使います。
networkは、未指定であっても、docker-compose内に記述された各コンテナは同じネットワークに配置されますが、各コンテナのIPアドレスをあらかじめ決めておきたい!という場合に指定します。今回は決めておきたいので指定しました。

同一ドメイン、別サブドメイン環境の実現

先にお伝えした「同一ドメイン、別サブドメインにて運用している」であったり「ALBのパスルーティングを用いて、特定URLなら新フレームワークが動作しているWebサーバへ、そうじゃないなら旧フレームワークが動作しているWebサーバへ、みたいな振り分け」みたいな事を実現するのに便利なイメージが提供されていて、今回それを使っております。
proxyというコンテナ名でymlには記載していますが、jwilder/nginx-proxyというイメージです。

このコンテナが、ローカルの80(http)と443(https)ポートに紐付いていて、ブラウザ等からローカルのWebサーバへアクセスするときの最初の受け口を担います。 コンテナの内、Webサーバを担うコンテナ(laravel-web、zend-front等)のenvironmentVIRTUAL_HOSTに、紐付けたいドメインを記述します。 例えば、ブラウザからlocal-admin.akippa.comってアクセスしたときにzend-adminのコンテナに向けたいのであれば、上述したymlのようにします。(別途、ローカルマシンのhostsファイルへ追記とかは必要です!)
また、複数のサブドメインを紐付ける事が可能で、その場合はlaravel-webコンテナのようにカンマ区切りで複数記述可能です。 これで「同一ドメイン、別サブドメインにて運用している」が実現できます。

ALBのパスルーティング環境の実現

次に「ALBのパスルーティングを用いて、特定URLならLaravelが動作しているWebサーバへ、そうじゃないならZend Frameworkが動作しているWebサーバへ、みたいな振り分け」の方法です。 local.akippa.comというのがそれをやってるサブドメインになります。 まず、local.akippa.comをVIRTUAL_HOSTに指定されているのは、zend-frontというコンテナになっています。これで、特に何も設定されていなければ、local.akippa.comはzend-frontに向くというわけですが、proxyというコンテナのvolumesセクションの記述に以下があります。

- $PWD/proxy/local.akippa.com:/etc/nginx/vhost.d/local.akippa.com

ここでjwilder/nginx-proxyというイメージが起動しているコンテナのNginxのlocal.akippa.comの設定ファイルに、ホスト側のファイルがマウントされています。(上記記述の左側がホスト、右側がコンテナのパス)
ホストマシン側にあるファイルの記述は以下のようになっています。(一部抜粋)

location = / {
    proxy_pass http://local-laravel.akippa.com;
}

location ^~ /others {
    proxy_pass http://local-laravel.akippa.com;
}

上記記述により、上の設定でトップページが、下の設定で/others配下のURLがlocal-laravel.akippa.comへ向かせる事ができます。
docker-compose.ymlを見るとVIRTUAL_HOSTにlocal-laravel.akippa.comと記述されているのがlaravel-webというコンテナになりますので、これで、上記のファイルに記述したパターンのURLであればLaravelが動作するWebサーバへ、そうでない場合はZendが動作するWebサーバへ向くというわけです。

HTTPS対応

HTTPS対応もしてます。
Docker上で構築したサイトは、本番で利用しているドメインと同じakippa.comとしています。
akippaでは、複数サブドメインで運用しているサイトが割とあるのでワイルドカード証明書を契約していて、それをそのまま使う事としました。
jwilder/nginx-proxyのコンテナproxyに対して以下のボリュームマウントをしています。

- $PWD/certs:/etc/nginx/certs

右側のパスがコンテナ側で、左側のパスがホストPC側ですね。ホストPC側に必要なファイル(秘密鍵(keyファイル)、証明書(crtファイル)とか)を置けばOKです。
このコンテナがブラウザとの最初のやり取りをする最初の受け口のALB的な役割を担ってくれているので、各コンテナに対して設定せずとも、これだけで済みます。

最後に

docker-compose.ymlに記述している内容で、Docker hubで提供されているイメージだけでなく、buildでこちらがカスタマイズしたイメージもあったり、もっと説明したい事あるんですが、話が長くなりそうなので、一旦この辺にしたいと思います!

Dockerは、ちょっと複雑な事をやろうとすると途端に難しくなるように思いまして、途中で挫折する方もいらっしゃるかもしれません。
今回、この構築作業に際し「さわって学ぶクラウドインフラ docker基礎からのコンテナ構築」っていう書籍を読んだのですが、結構わかりやすくて良い書籍だなーと思ったので、もしDockerの書籍に悩まれている方は一度手にとってみてください!

今後akippaに参画していただけるエンジニアさんやデザイナーさんの方々は、入社初日、Docker Desktopをインストールしてもらって、akippaのソースをgithubからcloneしてもらって、docker-compose up -dってコマンド打つだけでakippaの開発環境が一発で起動してくれるはずです!!(細かい事言うと、マイグレーションしたり初期データ入れたりいくつかやる事あるのでやや盛ってますが…笑)
ので、弊社求人へのご応募お待ちしております!!!!

この記事が気に入ったらサポートをしてみませんか?