ログ日記

作業ログと日記とメモ

スタートアップがPHPを使っていると聞いた話

この前、外国のスタートアップをやっている人にサービスを見せてもらった。
Qiitaによく書かれているような新しめのフロントエンドの技術盛り沢山で、クラウドや聞いたことのないようなサービスからTrelloのような知っているサービスなど色々使いつつ、なんかセンサー集計っぽい感じのWebが今風の画面でデザインされていた。他にもいくつかプロジェクト?があった。
VPNで海外の拠点に繋いで、遅いなーとか言いつつ。日本語は片言だったのであまり詳しくは聞けてないんだけど。
そういやブロックチェーンもやっていると言っていた。
よくある日本の零細企業ベンチャーじゃなくてガチのスタートアップや…とか思いつつ。

それで位置情報を使うからPostgreSQLを使っているだとか聞いて、あ、ネットで見た話だ、とかも思いつつ。


サーバーサイドは何?って話になって、PHPSymfonyだって聞いてびっくりした。
あれ?人気ないの日本だけ?
PHPは日本で?あまり人気ない感じなんですよねーとか言って、そうなの?なんでだろうね?なんて。
いや、そりゃーWordPressがあるから使われてる数で言ったら多いんだろうけど、新しいことやってる人にPHPは選択肢に上がってこないイメージだった。


まあ実際は驚きつつも、WebならPHPが一番手っ取り早いし、LaravelとかじゃなくてもSymfonyで十分というか、DBに近い部分で変に新しいものを選んだらメリットよりデメリットの方が大きいとか、PostGIS使うなら主流のORMの恩恵あまり無いよねとか、ロジックはどんどんフロントエンドに行くからPHPで複雑なプログラミングはしないよねとか、色々思いつつ。

そんな話を聞いたあとに
https://qiita.com/dossari-book-archive/items/ad4f7bcaaebca6281154 こことか
https://qiita.com/charmston/items/df31a419a4e57ebe86ba こことか読んで、ちょっともやもやした。


ただPHPは言語自体を勉強するという感じのものではないのは確かだし、たぶんそのスタートアップの人もPHPでこんな面白いプログラムを作った!とは言わないと思う。知らんけど。


自分も毎日PHP書いてるけど、特に記事に書くようなこともなく。
PHPで関数の末尾呼び出しを最適化する - Qiita 書いてもネタみたいになっちゃう。
本当はネタじゃなくて真面目にHTML解析タイプのテンプレートエンジンを作りたいんだけども。今は使いどころがないんよね。10ページ程度のサイトをいくつも作るような会社に居るなら完成まで作ったのかもしれない。

あ、DIコンテナ https://github.com/nishimura/simple-container とか https://github.com/nishimura/db-migration DBバージョン管理ツールは最近作ったんだった。作ったというか、作っていたものを小さく整理した。
最近はとにかくシンプルにしようと思っていて、たかだかコンテナやDBツールで何ファイルも何千行もあるライブラリを読み込むのは無駄じゃん?と思って必要な機能だけ切り出した感じ。なので特に書くことが無い。


そういうわけで、PHPは新しい環境でも普通に使われているけど使われ方が普通すぎて特にアピールすることもないので不人気に見えるのでは?とか思った。
ぐだぐだ書いておいてn=1だけどね。


最近のPHPは、スカラー型からnullableな型、そしてついにTyped Properties とか、かなり大きな変更の流れですごいことだと思ってるんだけど、便利な新機能!ってことじゃなくてじわじわくる感じだからなあ。
LaravelでURLルーティングからの引数に直接DB Entityを差し込むやつ、あれのプロパティ版がはかどるんじゃない?と思ってるんだけど。
そのDB Entityも型があったらDBのnullableをそのままマッピングできて、JavaっぽいのにJavaよりすごくない?とか。


オレオレフレームワークばかりだった頃からLaravelとかCakePHPとかSymfonyとかに統一されてきて(それでも数が多いけど)、何かPHPの記事を見かけてもライブラリの使い方の説明だけなのが寂しい感じはある。

うーん、なんだかまとまらないままポスト。

さくらクラウドでsystemd-nspawnを使う場合のネットワーク設定

IPが一つの場合

選ぶ余地もなく --network-veth のプライベートネットワーク。
/etc/systemd/nspawn/guest1.nspawn などのファイルに

[Network]
Port=80:80

と書くと元々あったIPマスカレードに加えてポートフォワードが設定されるので、ポート競合が起きない状況だと便利。
ゲストの自動的に設定されたIPにフォワードしてくれる。

ルータ+スイッチ配下で複数IPを使う場合

https://n314.hatenablog.com/entry/2018/09/29/134220
ここの続き。


一つのMACアドレスに対して複数のIPを割り当てる必要があるのが何とも悩みどころ。
ホストOSにIPを複数割り当てつつ上で書いたポート転送で

[Network]
Port=172.17.0.3:80:80

docker-composeのように書ければそれが一番楽だったんだけど、これは無理だった。


取り敢えず以下の2パターンにするしかなさそう。

ネットワーク共有

ホストOSのネットワークを共有する。
IPをホストOSで複数割り当てつつ、ゲストはその中の一つを使う。

ネットワーク絡みの問題が何も起きないが、サーバー絡みの問題が起きる。
大抵の設定ファイルには

Listen *
ListenAddress 0.0.0.0

のようになっているので、これをゲストOSのIP割り当てを考慮して変更していかないといけない。
ip a でIP一覧を出すとゲストOSの分全て表示されるので数が増えるとややこしい。

あと 127.0.0.1 も競合する。localhost を 127.0.0.2 とかに変えていけばいいんだろうけど、アプリによってはIP固定で書かれていたりしそう。

ipvlan

ipvlanでは --network-ipvlan=eth0 のように設定してMACアドレスを共有しつつ、新しいNICがゲストに作られる。
ホストにIPが割り当てられないし、ゲストにログインして ip a すると自分のIPしか表示されずブリッジっぽくなっている。
ただし普通のブリッジではないので ゲストとホストは通信できない模様。
systemd-nspawnで外部からssh可能でnvidia GPUを使えるコンテナを作る - Qiita
ゲスト同士は通信できる(なんで?)

ログサーバーをゲストに立ててるんだけど、そこにホストのログを送れない。
まあその一点以外はブリッジ接続と同じ感じで使えるので、ホストはただの箱として以外使わないようにして取り敢えずこれで試してる。

プライベートネットワーク+ルーティング

NATとかマスカレードとかフォワードを自分で設定。
いちいちゲストの設定変更時にホストのルーティング変更をするのは大変そう。なので試していない。
最後の手段。

ローカルでDocker を使って GitLab CIを設定するのは鬼門だった

普通に公開用のドメインでやるより相当ハードルが高かった。というか一部動かず解決しなかった。

  • docker-compose.yml の名前で解決できることと出来ないことがある
    • CIでDockerを走らせる場合は、(GitLabを立ち上げる docker-compose.ymlではなく)GitLab Runner の設定でextra_hosts を設定する必要がある
    • GitLab Runner がプライベートのDocker Registry からイメージを取ってくるとき、名前解決できる必要がある
      • GitLabの/etc/hosts も GitLab Runner の/etc/hosts も GitLab Runner が立ち上げた /etc/hosts も見てくれない? 名前解決用のサーバー的な何かを別途追加する必要があるかもしれない(未解決)
      • なんか GitLab Runner がDockerを起動するための golang が /etc/hosts を見ないとか、 /etc/nsswitch.conf を設定しろとか issue があったけど、うまく設定できず
  • 各所でSSLが必須
    • Let's Encrypt で適当なサブドメインを作って証明書を持ってくると解決できる
    • https-portal とか ansible とか使ってほとんど自動化できるけど、簡単に自動化しすぎると今度は Let's Encrypt の Rate Limit に引っかかったりする。
    • サブドメインを多く使う場合は、Let's Encryptはサーバーに直接入れて複数ドメインのSANs証明書を手動で取るのが良いかもしれない。

golang の名前解決方針とかGitLab Runner の仕組みとか知りたいわけではなくて、単にローカルでCIのテストをしたいだけなんだけど…全然たどりつかない。ということで一旦諦めて普通に名前解決できるドメインでやった。


GitLab を Docker で入れて、Docker Registry を Dockerで入れて、連携するネットワークの部分を書いて、設定ファイルを上手く連動するようにやって、SSLなどでエラーが起きないようにして、などなど。
もしかすると普通に apt-get で GitLab Omnibus を入れたら一瞬で解決したのかもしれない。
確かにDockerを使えば単品の構築は楽で一瞬で立ち上がるが、それぞれの連携がつらい。エラーが見えづらい。オールインワンパッケージがあるなら、それを入れるのが良さそう。


プロダクション環境でDockerを使うためには、今GitLabで苦労したようなことを自前システムでもやるってことだよねえ…。
まあ最初からDockerで使うように作る場合とパッケージ提供ベースをDocker対応するのとでは全然違うのかもしれないが。

ローカル仮想マシンのDockerでも簡単にLet's Encryptを使いたい

今まではLet's Encryptで local.example.com とかのグローバルサドメインを設定して、それをrsyncで持ってきてローカル用に使ってた。
これを自動化する。

test.example.comドメインに対する test.local.example.com は空でいい。

version: '3'
services:
  proxy:
    image: steveltn/https-portal:1.4.2
    ports:
      - '80:80'
      - '443:443'
    restart: always
    environment:
      DOMAINS: >-
        test:example@test.example.com #production,
        test:example@test.local.example.com #production
    volumes:
      - '/srv/https-portal/certs:/var/lib/https-portal'
      - '/srv/https-portal/vhosts:/var/www/vhosts'

これをテストサーバーで立ち上げ。


ansibleのタスク

---
- name: copy ssh keys
  copy:
    src: "~/.ssh/{{ item }}"
    dest: "/root/.ssh/{{ item }}"
    mode: 0600
  with_items:
    - id_rsa
    - id_rsa.pub
  when: inventory_hostname == 'test.local.example.com'

- name: debug
  debug: "msg={{inventory_hostname}}"

- name: rsync certs from remote local
  synchronize:
    src: /srv/https-portal/certs/
    dest: /srv/https-portal/certs/
    mode: pull
    recursive: yes
  when: inventory_hostname == 'test.example.com'
  delegate_to: test.local.example.com

inventoryにipやポートを書いて

ansible-playbook -i local -u root -v playbook.yml
ansible-playbook -i remote -u root -v playbook.yml

既にsshの公開鍵があり local => remote の sshが通るなら上側は不要。
synchronize の pull を delegate して実行する。(ややこしい)


docker-compose up -d の前にこのplaybookを実行すれば、証明書が更新されている場合はダウンロードしてくる。(予定)


最初の docker-composeの

        test:example@test.example.com #production,

の行を削除して、ローカルでもproductionで立ち上げる。linkとかあるなら test.local.example.com の方に移植する。

/etc/hosts のドメイン省略形は後ろに書かなければならない

初めて知った。というか前に書いて不具合が出た。
何となく習慣で

127.0.0.1	host1.example.com	host1

って書いてたけど、Ansibleで設定していたときに

127.0.0.1	host1	host1.example.com

と書いていた。
そうすると hostname -f で正しくドメインが引けない。


debian/Ubuntuの/etc/hostnameにはFQDNではなくshort nameを書く | Nekoya press
Chapter 3. The system initialization

/etc/hostname にドメインまで全部書いてしまうと、今度は(-fなしの) hostname でドメインまで出てしまう。
hostnameコマンドでチェックしない限り、普段使ってる分には特に問題は起きないので気付かなかった。


いやでも man hosts で

              IPアドレス 正式なホスト名 [エイリアス...]

       エントリーのフィールドは、空白またはタブ (複数でも可) で区切られる。 "#" 文字から行末までのテキストはコメ
       ントとして無視される。 ホスト名は英数字、 マイナス記号 ("-")、 ピリオド (".") を含むことができる。 ホスト
       名は英文字  (alphabetic character) で始まって、 英数字 (alphanumeric characte) で終わらなければならない。
       エイリアスはオプションであり、名前の変更、別のスペル、   短いホスト名、一般的に使われるホスト名   (例えば
       localhost) などのために用意されている。

正式なホスト名はhost1で、host1.example.comドメイン名込みのエイリアスとも考えられるから、ちょっと意味が分からない。



最近manコマンドをよく使う。

man systemd.netdev
man systemd.link
man systemd-hostnamed.service

systemdの情報ってブログとかには全然なかったり不完全だったりするので、man見た方が早かったりする。

さくらクラウドでbrctlなどでeth0にブリッジする(失敗)

[追記]
下の設定は意味がなかった。


ブリッジに新しいNICを接続するとき、やはり別のMACアドレスが必要になる。
でもそのMACアドレスでは外に出れないので、ローカルネットワークと同じような状態になって意味がない…。

ブリッジに接続する新しいNICまで同じMACアドレスにするのは無理だし、結局仮想を動かすにはルーティングするかNIC共有するかのどちらかになるっぽい。
[/追記]


新しくbr0を作ってそこにeth0を繋げても動かなかったのでメモ。


manual.sakura.ad.jp
MACアドレスが固定らしい。


ブリッジ接続を新しく作ると、eth0のIPが消えてbr0にIPを設定する。
このときbr0は新しくMACアドレスが作られるので、それで通信できていない?


eth0と同じMACアドレスにすると通信できた。
同じMACアドレスでいいのかは分からないが…。
serverfault.com
KVMの場合だけど、ブリッジだと問題なさそうというか同じにするべきだというふうに読める。


unix.stackexchange.com
この辺の回答とコメントを読んだけどよく分からない。


bridge - wlan same mac adress - loop - MikroTik
こっちでは問題が起きてるっぽいけど、Maybe a bug? と言われている。


ネットワークの問題というよりもLinuxの仮想NIC実装の問題だろうか。
ネットワークのループは実機でも仮想でもやったことあるけど、その場合すぐ制御不能になるので今動いているということは大丈夫なんだろう。たぶん。

debian9 の systemd-nspawnでdockerを動かす準備

デフォルトの設定では動かなかったので調べる。
https://wiki.archlinux.org/index.php/systemd-nspawn#Run_docker_in_systemd-nspawn


権限の設定が必要な模様。
それでもエラーが出たので、systemd-nspawnコマンドで起動してみる。
SystemCallFilterは --system-call-filter のオプションなんだろうなと思って検索しつつ。


https://man.kusakata.com/man/systemd-nspawn.1.html
オプションはある模様。
だけどdebian stretchでは認識されてない。



https://github.com/systemd/systemd/issues/5163
比較的最近の機能のようで、stretch-backports を探してみる。


https://packages.debian.org/stretch-backports/systemd-container
あった。このバージョンに上げたら使えるんだろうか。
apt-get -t stretch-backports で入れたり、戻したりした。
ダウングレードは

apt-get install systemd-container=232-25+deb9u4 \
  libnss-mymachines=232-25+deb9u4 \
  systemd=232-25+deb9u4 libsystemd0=232-25+deb9u4

のようにstretch-backportsでバージョンアップされた依存関係のあるものを個別にバージョン指定する必要がある?


docker run hello-world が動いたので
https://docs.ansible.com/ansible/latest/modules/apt_module.html
ansible の aptでdefault_releaseを指定してインストール。


これで docker in systemd-nspawn 完了。
あとはdocker-machineなりsshなりして systemd-nspawnのコンテナの中からdockerコンテナを立ち上げられるようになる。