調子に乗ってentrypoint.shのshebangを省略しない

元気に$podman runしたところ、下記のようなエラーが出た

standard_init_linux.go:211: exec user process caused "exec format error"

一体何を...バイナリでも壊したかな.......みたいな気分だったが、Dockerfileで最後のCMDとして指定している

CMD ["./entrypoint.sh"]

entrypoint.shの中身が

cd exapmle
python main.py

みたいなシェルスクリプトで、 戦闘に#!/bin/shが無いという落ちだった。。。 ぐぐると様々な人間が引っかかっている。普通のスクリプト言語でプログラミングするときは省略しないはずなのに、やはりdockerスクリプトを書くときみたいな勢いでエイヤしてるときは引っかかりがちなので、気をつけていきたい...

www.lewuathe.com

Rustで文字列が数値かどうかの判定

String変数を.parseしてOkかErrかどうかで判定可能。 たぶん<u8>じゃなくて<u16>とかにすると範囲が拡大する。

    let name = match name.parse::<u8>() {
        Ok(_) => String::from(format!("{}-{}", user_name, name)),
        Err(_) => name,
    };

この例だと数値が来ていた場合はuser_nameとハイフンで結んだ文字列をnameにshadowingしている。anatofuz-01的な感じ。

ISUCON10に出場して再起動試験で泣いてきました

ISUCON10にチームINJとして学生枠で出場し、結果としては学生本戦出場枠には入っていましたが、再起動試験で失格でした。

isucon.net

今年は最後の学生枠みたいなところがあったので、まぁ思い出づくりも兼ねて id:unimarimo (jogo)と研究室の後輩でありシス管のmkくんと出場しました。ちなみにチームは id:unimarimo以外は初参加。

シス管メンバー集結みたいな形になったのだけど、なんとisuconの予選と大学のネットワーク機器の入れ替え工事日が被ったので関係各所にはご迷惑をおかけしました...。ちなみに今回は各自自宅からzoom繋ぎっぱなしで参戦しました。

ちなみにチーム名INJはIikanji Na Jogo の略です。

f:id:anatofuz:20200913045123j:plain

役割分担としては

  • AnaTofuZ
    • 全体, 声掛け
    • webapp
  • Jogo
    • インフラ全般
  • mk
    • 遊軍

みたいな感じでした。 特にJogoくんがインフラ専門として活躍していて、マルチに活躍できるmkくんが遊軍としていろんな領域を見れていたのは良かった気がする。

やったこと

まとめると

  • チームの声掛け
  • デプロイスクリプトの用意
  • ヤバそうなエラーの解決要因
  • dlvを投入してのデバッグ
  • jsonライブラリの変更
  • 細々したSQLの変更
  • いらんORDER BYの削除とか

このあたりをしました

だいたい時系列ごと

2hの猶予が与えられたので、シェルでデプロイスクリプトをしこむ。わりと便利だったのでやってよかった。

ポータルが508騒ぎの中、「当日マニュアルはdiscordにURLがあるぞ」という話になり、みんなでポータルが復旧するまでマニュアルを音読していた。

「とりあえず椅子と資料請求させとけばええんか」「なるほどな」みたいな話をしていた。あとここでBot対策が重要そうだけどまだ実装されてないとかあるので、実装せないとな.....みたいになった。

ポータル回復後みんなでsshまつりをする。ssh先のIPの計算ができなかったが、mkくんがバシッと運営のconfigをupdateしてくれてそれを使うことになった。ポートフォワーディングのconfigの書き方とsshコマンドの使い方を理解する。

gitリポジトリ化とpprofとgo-sql-proxyをしこみ(mysql:proxyの書きミスとかがあり手間取ったが)大体開始1hちょいくらいには全体のボトルネック等をチームで共有した。アクセスログはalpが上手く読めず、全体を通して活用できてなかった。どうもUserAgent周りとアクセス先のエンドポイントが重要そうだったので、ちゃんと見るべきだった気がする。

pprofの結果json関連とnazotteがネックになっていることがわかったので、golangで使っているjsonライブラリを github.com/goccy/go-json にひとまず切り替えるなどを仕込んだ。そこまでスコアが上がらなかった気もするが...。

github.com

なんとなくテンプレートがねぇなという話になり、そもそもこの画面はどこから来ているかを探したところ、「あっ静的HTMLでjs経由か!?」みたいな話になる。「えっ画像もほとんどこのディレクトリじゃん.......」と連鎖的に確認し、jogoくんにnginxのキャッシュとgzip等の最適化を依頼する。

そういえばbotの解決もするかと思い、軽くググるとuser-agentのブロックはnginx側で出来るらしいので、jogo先輩に脳筋if文コピペを以来する。

nazzoteのN+1を解決すれば伸びそうというのはわかったものの、JOINするわけでもないので「ぐぐぐ......」となり、とりあえずSELECT *している不毛な箇所を消してまわろうという作戦に出た。一箇所の変更は問題なくて、ある程度いい感じになった。

ここで調子に乗って「表示に影響しないJSONの要素も落とすか」となったが、この施策をし始める前後でベンチが何も言わず死ぬ減少が多発する。いろいろロールバックしていたが状況がわからず、運営に問い合わせたり色々していたところ、mkくんがレギュレーションに「JSONの変更はNG」との文脈があることを発見。泣きながらロールバックする。ここでだいぶ時間をとられた......。

jogo先輩とmkくんが作ったindexのsyntax errorを解消していたり、自分のSQLのsyntax errorを解決していたりもしていた。デバッグしたかったので本番にgolang 1.15とdlvをいれて気合で見ていたけれど、このへんがあんま良くなかったかも知れない。

index周りだとSELECT * FROM estate ORDER BY rent ASC, id ASCみたいなクエリのindexを有効化しようと頑張っていたが、FORCE INDEXしないとindex貼られないという事件に遭遇していた。感想を見る限りMySQL8を使うかデータ構造に手をいれるのが大正解だったらしい。ぐぐぐ。。。

終盤でMySQLのクエリキャッシュが結構聞くことがわかったので、2台目をDBサーバーにするという背策をjogoとmkくんに頼み、ベンチマークを回していくと過去最高の1200台を記録。かなり盛り上がった。

レギュレーションで学生が上位25チームに入ればそれを除いた学生上位5チームが本戦出場なので、ギリギリいけるかな〜みたいな話をしていた。結果はギリギリ行ける枠にはいたのだけど、再起動試験で失格でした。再起動チャレンジやってなかったので痛いところ。まぁ再起動しても気づいたかどうかは別っぽい。

所感

ということで学生最初で最後のisuconでした。チーム運用もめちゃくちゃ良くて、ギスギスせずに進められたので良かった気がする。(configのコピペ忘れをしたjogo先輩に「舐めプか?」と煽ったのはノーカン)

全然俺はSQLもHTTPもわからん.....なにも...........。みたいになったので、webの勉強ちゃんとしないとなぁと思いました。細々した修正を中心にやってしまい、もう少し責めのコミットができるくらいの知識が必要でした。特に序盤ではsqlx関係のエラーを多発させてしまい、「sqlライブラリの慣れと、SQLの知識が必要だったな.....」と痛感しています。N+1は最初に気づいたにも関わらず、解決できなかったのが痛いです。他にもなんとなく改善できそうなとこは何個かあったけど、歯が立たなかったです。。。nazotteの改善でいろいろミスを踏みましたが、dlvいれてからは冷静に対処できたのでそこは良かった、そもそもミスをしたのは、経験値不足なのでツラミですね。。。

他にはテーブルが2つなのでDBを分けるという話がrandomチャンネルにありましたが、思いつかなかったですね。

あんまり練習時間が取れなかったチーム(全員シス管なので)+初めてのisuconでしたが健闘できたのは良かったですね。もちろん学生上位とのスコア差は大きいですが、普段からweb専門にやってる人がいないチームで1000点超えれたのは大きい気がする。これはid:unimarimoとmkくんの働きがすごかったというのがほとんどですね。これで本戦に行っていればもっと良かったので再起動試験が悔やまれます。一度再起動試験を試すべきだったな.....。ちなみに再起動試験のどこで死んだのかは調査中です。(どうもベンチで使ってたサーバー以外の方をみられていたらしく、そっちはnginxを動かしていた為に勘違いされた or そいつがDBを使いにいってベンチ側のサーバーからDBにアクセスできなかったのではという話を推測しています)

全員就職先の土地がバラバラなので、次回このチームになることはオンライン開催でない限り無理ですが、チームとしても良い経験になったかなと思います。シス管の作業頑張っていこうな...。

チーム関連だと他メンバーへの声掛けとか詰まってるとこを協力して解決ができてよかったです。ISUCON夏期講習の「手が止まっている時間を作らない」がちゃんとできたのはチームに貢献できた点かなぁと思います。

次回のisuconがあれば社会人枠ですが、ここで本戦出場目指してやっていきましょう。バンバンスコア上げたいしもっと貢献したいね。。。。現場からは以上です。

openldapはldapsの代わりにldapを使っていても死なない

今日のツラミポイント。

学科で運用しているOpenLDAPサーバー(slapd)の設定(slapd.conf)で詰まったやつ。 別で作成したslapdをプロバイダにして、いままでプロバイダだったslapdをコンシューマーにしようと、設定を書いていた。

overlay syncprov

syncrepl rid=104
        provider=ldap://example.com:389
        bindmethod=simple
        binddn=""
        credentials=""
        searchbase="ou=ie,o=u-ryukyu,c=jp"
        schemachecking=on
        type=refreshAndPersist
        retry="60 10 300 3"
        tls_reqcert=never
        interval=00:00:00:01


# ミラーモードを有効化
mirrormode on

これでsystemctl restart slapdすると、何もエラーを出さず元気に立ち上がるものの ldapsearch -x uid=anatofuzとかすると綺麗に何も出ていない。 どうもデータベースになにも書き込まれていない状態だった。

ldapsearch-Hでプロバイダを指定するとちゃんと引けるので、困ったね.....となっていたが、落ちはタイトルの通りで

        provider=ldap://example.com:389

ではなく

        provider=ldaps://example.com:389

じゃないといけないというショッパイ落ち.........。気をつけようね。。。。。

ubuntu上にOpenLDAPの構築

学科というか琉大では学生のアカウント管理にLDAPを使っている。 学科の場合はセンター(大本)のLDAP情報を同期した、学科システム上に構築したslapdをLDAPサーバーとして活用している。

今年は学科システムの式年遷宮の年なので、Centosで従来動いていたシステムを参考に、UbuntuOpenLDAPを構築した。

すでにDocker環境はakatsukiの構築で作っていたのだけれど、とりあえず安心感のあるVMopenldapの構築をしたかったので、ansibleを書いていた。

init.ldifとかは現在動いているLDAPのバックアップ。

---
- name: install ldap
  become: yes
  apt:
    name:
      - slapd
      - ldap-utils
  environment:
    DEBIAN_FRONTEND: noninteractive

- name: copy ldap.conf
  become: yes
  copy:
    src: ldap.conf
    dest: /etc/ldap/ldap.conf
    owner: openldap
    group: openldap
    mode: 0664

- name: copy slapd.conf
  become: yes
  copy:
    src: slapd.conf
    dest: /etc/ldap/slapd.conf
    owner: openldap
    group: openldap
    mode: 0640

- name: copy schemas
  become: yes
  copy:
    src: schema
    dest: /etc/ldap/
    owner: openldap
    group: openldap
    mode: 0644

- name: copy init.ldif
  become: yes
  copy:
    src: init.ldif
    dest: /tmp/init.ldif
    owner: openldap
    group: openldap
    mode: 0664

- name: copy DB_CONFIG
  become: yes
  copy:
    src: DB_CONFIG
    dest: /var/lib/ldap/DB_CONFIG
    owner: openldap
    group: openldap
    mode: 0664

- name: remove /etc/ladp/slapd.d/cn=config
  become: yes
  file:
    path: /etc/ldap/slapd.d/cn=config
    state: absent

- name: slapadd -f /etc/ldap/slapd.conf
  become: yes
  command: echo '' | slapadd -f /etc/ldap/slapd.conf

- name: stop slabd
  become: yes
  systemd:
    name: slapd
    state: stopped
    daemon_reload: yes
    enabled: yes

- name: chown cn=config
  become: yes
  file:
    path: /etc/ldap/slapd.d/cn=config
    state: directory
    recurse: yes
    owner: openldap
    group: openldap

- name: chown /var/lib/ldap
  become: yes
  file:
    path: /var/lib/ldap/
    state: directory
    recurse: yes
    owner: openldap
    group: openldap

- name: slaptest
  become: yes
  become_user: openldap
    # ignore_errors: yes
  command: slaptest -f /etc/ldap/slapd.conf -F /etc/ldap/slapd.d

- name: slapadd -l /tmp/init.ldif
  become: yes
  command: slapadd -l /tmp/init.ldif


- name: enable slabd
  become: yes
  systemd:
    name: slapd
    state: restarted
    daemon_reload: yes
    enabled: yes

openldapはaptでslapdを指定すれば入るけれど、 DEBIAN_FRONTEND: noninteractiveを指定しないと上手く入らない(唐突にGUI的なあの画面が出てくる)のが注意点。

詰まったのは slaptest -f /etc/ldap/slapd.conf -F /etc/ldap/slapd.dする時にopenldapユーザーでやらないと、/var/lib/ldapの中で生成されるBerkeley DBのパーミッションが変になること。

解決方法としてはbecome_useropenldapを指定し、プロジェクトルートのansible.cfgに次の用に書く。

[defaults]
allow_world_readable_tmpfiles=true

微妙に再起動するとパーミッションが異なるとかはあったが、まぁ大丈夫だろうと信じている。。。

新鮮なFedora32にwordpressを構築するansbile

ということで書きました。OSの課題で使ういつものやつです。

ie.u-ryukyu.ac.jp

もともとは先輩が書いていたものですが、今年はシステム更新などでapacheを学科から追放したい気分があったのでnginxでリライトしました。といいつつ大体先輩のコードをそのまま使ってます。(ありがとうございます)

otnk1122.hatenablog.com

Fedora32で動くのを確認したので新鮮なFedoraでどうぞお試しください。

色々と改善していて、まずtasksに書いていたものをrolesにしたりとか、デーモンの再起動にnotifyを使っています。このあたりはisuconのansibleを参考にしました。

nginxでwordpressを動かしたいのでphp-fpmを入れていますが、本当にunix domain socketで通信をしているかが怪しい気がする。多分大丈夫だとは信じたいですが。

なにかツッコミがあればよろしくお願いします。(それを改善するのがB2の課題になる気がする)