ICTSC2021 夏の陣に参加しました
はじめに
2021年08月の28(土), 29(日)で開催された ICTトラブルシューティングコンテスト2021 夏の陣(ICTSC2021 Summer) に参加しました。
チーム名は「add忘れ VLAN全消し 疎通なし」です。 本番は自分含め3人で参加しました。
(2021/08/30追記) 全体4位でした。入賞圏内だったと思うので、悔しいですね... ただ、本番終了のタイミングでは6位だったのですが、最後にチームメイトが提出した解答が部分点を貰うことができたようで4位に上がることができたようです。 チームの皆さんありがとうございました🙇
備忘録的なものとしてどんな問題をどう解いたのかを書き残したいと思います。 (後から問題が公開されると思うんですが、環境自体は自分の手元で再現出来ない可能性が高そうなので、覚えている限り思考の手順が残せれば嬉しいです)
私が解いた問題は以下のとおりです。
- 2 頑固なindex.html(150)
- 6 iscsi targetにログインできない!(200)
- 8 アドレスが配布できない (200)
- 9 止まらない (50)
- 11 ャッシュサーバ立てたけど(250)
- 12 Webサイトにアクセスできない(200)
- 13 サーバ天気予報 (150)
- 14 Webサーバが立ち上がらない(50)
- 15 ンジンエックス(150)
2 頑固なindex.html (150点)
/var/www/html/index.html
を変更した後、マシンを再起動すると元のファイルに戻ってしまう、という現象が生じていました。
最初はcron
とかで上書きしているのかと思ったのですがcron
には何も定義されていませんでした。
ならばサービスが何かやっているのかなと思い、/etc
以下を探してみると、/etc/tmpfiles.d/ictsc.conf
に怪しげな記述が見つかりました。
/etc/tmpfiles.d/ictsc.conf
F /var/www/html/index.html 0777 root root - Welcome to ICTSC
どうやらsystemd-tmpfiles
が悪さをしていたようです。
上記の部分をコメントアウトすることで、解決することが出来ました。
6 iscsi targetにログインできない! (200点)
iscsi何も分からない...と言いながら解いていました。
iscsi-targetに対してclientからログインしようとするシナリオとなっており、 以下のコマンドを打ってログインを試みたところ、ログインに失敗してしまう、というを解消する問題でした。
client$ sudo iscsiadm -m node --login Logging in to [iface: default, target: iqn.2021-07.192.168.18.2:target, portal: 192.168.18.2,3260] (multiple) iscsiadm: Could not login to [iface: default, target: iqn.2021-07.192.168.18.2:target, portal: 192.168.18.2,3260]. iscsiadm: initiator reported error (24 - iSCSI login failed due to authorization failure) iscsiadm: Could not log into all portals
iSCSI login failed due to authorization failure
と怒られていることから、認証系の何かが間違っていそうだと見当をつけました。
iscsi-target$ $ sudo targetcli /iscsi/iqn.20....11:initiator> ls o- iqn.2021-07.192.168.18.11:initiator ............................................................................ [Mapped LUNs: 1] o- mapped_lun0 ......................................................................................... [lun0 fileio/disk01 (rw)] /iscsi/iqn.20....11:initiator> ls / o- / ......................................................................................................................... [...] o- backstores .............................................................................................................. [...] | o- block .................................................................................................. [Storage Objects: 0] | o- fileio ................................................................................................. [Storage Objects: 1] | | o- disk01 .................................................... [/var/lib/iscsi_disks/disk01.img (5.0GiB) write-back activated] | | o- alua ................................................................................................... [ALUA Groups: 1] | | o- default_tg_pt_gp ....................................................................... [ALUA state: Active/optimized] | o- pscsi .................................................................................................. [Storage Objects: 0] | o- ramdisk ................................................................................................ [Storage Objects: 0] o- iscsi ............................................................................................................ [Targets: 1] | o- iqn.2021-07.192.168.18.2:target ................................................................................... [TPGs: 1] | o- tpg1 ............................................................................................... [no-gen-acls, no-auth] | o- acls .......................................................................................................... [ACLs: 1] | | o- iqn.2021-07.192.168.18.11:initiator .................................................................. [Mapped LUNs: 1] | | o- mapped_lun0 ............................................................................... [lun0 fileio/disk01 (rw)] | o- luns .......................................................................................................... [LUNs: 1] | | o- lun0 ............................................. [fileio/disk01 (/var/lib/iscsi_disks/disk01.img) (default_tg_pt_gp)] | o- portals .................................................................................................... [Portals: 1] | o- 0.0.0.0:3260 ..................................................................................................... [OK] o- loopback ......................................................................................................... [Targets: 0] o- vhost ............................................................................................................ [Targets: 0] o- xen-pvscsi ....................................................................................................... [Targets: 0]
ACLを見るとiqn.2021-07.192.168.18.11:initiator
となっていることが分かるため、clientの認証情報を照らし合わせます。
設定は/etc/iscsi/initiatorname.iscsi
にありました。
以下のように変更します。
... InitiatorName=iqn.2021-07.192.168.18.11:initiator
再度ログインを試みて、ログインに成功することを確認できました。
$ sudo systemctl restart iscsid $ sudo iscsiadm -m node --login Logging in to [iface: default, target: iqn.2021-07.192.168.18.2:target, portal: 192.168.18.2,3260] (multiple) Login to [iface: default, target: iqn.2021-07.192.168.18.2:target, portal: 192.168.18.2,3260] successful. $ lsblk | grep -E "(NAME|sda)" NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 5G 0 disk
8 アドレスが配布できない
IPv6のアドレスがDHCPサーバから上手く設定されない、という問題でした。 (正直動いたからヨシ!という感じで何も理解できていないので後で調査します...)
以下の3つの手順で解決しました。
isc-dhcp-server6
が動いていなかったので、configを書いて立ち上げる- RAも広告したいので、
radvd
を立ち上げる net.ipv6.conf.all.forwarding = 1
をsetする
isc-dhcp-server6.service
の起動
まず/etc/defalut/isc-dhcp-server
を編集します。
DHCPDv6_CONF=/etc/dhcp/dhcpd6.conf DHCPDv6_PID=/var/run/dhcpd6.pid INTERFACESv6="eth1"
変更した設定を適用します。
$ sudo systemctl enable isc-dhcp-server6 $ sudo systemctl restart isc-dhcp-server6
radvd
の起動
さらに、radvd
を設定します。
/etc/radvd.conf
interface eth1 { AdvSendAdvert on; MinRtrAdvInterval 3; MaxRtrAdvInterval 10; AdvOtherConfigFlag on; prefix fc01:1:1:1::/64 { AdvOnLink on; AdvAutonomous on; AdvRouterAddr on; }; };
正直設定の意味はあまり分かっていないのですが有効化します。
$ sudo systemctl enable radvd.service $ sudo systemctl restart radvd.service
net.ipv6.conf.all.forwarding = 1
をsetする
たしかradvd.service
のstatusを見たら「forwardingしなさい!」みたいなWarningが出ていたため、対応します。
以下の内容で/etc/sysctl.d/99-dhcp-server.conf
を作成します。
net.ipv6.conf.all.forwarding = 1
これをsudo sysctl -p /etc/sysctl.d/99-dhcp-server.conf
で適用します。
radvd
を再起動してserverの設定は終了です。
あとはclient側で sudo dhclient -6
を実行するとアドレスが降ってきて、pingが通るようになったことを確認できました。
9 止まらない(50点)
フレームワークGinを使って作成されたシンプルなWebサーバをgoで立ち上げるシナリオです。
docker run .... go run main.go
みたいな感じで立ち上げられるのですが、Ctrl + C
で止めることが出来ない、という問題を解決する課題でした。
https://docs.docker.com/engine/reference/run/#foreground によると、
A process running as PID 1 inside a container is treated specially by Linux: it ignores any signal with the default action. As a result, the process will not terminate on SIGINT or SIGTERM unless it is coded to do so.
となっており、
Ctrl+Cで終了できない、という問題は、docker run
コマンドで起動するプロセスがあらゆるシグナルが無視することが原因だと考えました。
そのため、-it
オプションを付与しました。
また、そのままではWebサーバは正常終了することができないため、以下のようにシグナルを待ち受けるよう、(前提条件「host上に追加でパッケージをインストールしてはいけない。」を満たすように)変更を加えました。
diff main.go main.go.bk 7,10d6 < < "log" < "os" < "os/signal" 18,42c14 < server := &http.Server{ < Addr: ":8080", < Handler: r, < } < < quit := make(chan os.Signal) < signal.Notify(quit, os.Interrupt) < < go func() { < <-quit < log.Println("receive interrupt signal") < if err := server.Close(); err != nil { < log.Fatal("Server Close:", err) < } < }() < < if err := server.ListenAndServe(); err != nil { < if err == http.ErrServerClosed { < log.Println("Server closed under request") < } else { < log.Fatal("Server closed unexpect") < } < } < < log.Println("Server exiting") --- > r.Run(":8080")
以下のように変更を行うことで、Ctrl+Cで正常終了することが出来ます。
11 キャッシュサーバ立てたけど(250点)
DNSに関する問題です。(多分)
キャッシュサーバを立てたのにも関わらずgethostbyname()
が実行されてもキャッシュサーバに問い合わせが行われない、という問題でした。
外部DNS(/etc/resolv.conf
で指定されているリゾルバ)よりsystemd-resolved
が優先させるように変更を加えます。
まず/etc/nsswitch.conf
のhost:
で指定されている部分を以下のように書き換えます。
#hosts: files dns hosts: files resolve [!UNAVAIL=return] dns
そしてsystemd-resolved
を再起動することで、終了状態を満たします。
個人的に一番勉強になった問題でした。
12 Webサイトにアクセスできない(200点)
k8sに関する問題です。
Ingressでサービスを公開したが、curl -k https://<loadbalancer IP>
とすると502レスポンスが返ってくる、という問題です。
確かまずはじめに、
ingress
のログを見ると upstream sent too big header while reading response header from upstream
みたいなエラーが出ていることを確認したと記憶しています。
proxy-buffer-size
が8Bしかない状態だったので、適当な大きさまでproxy-buffer-size
を上げました。
変更を適用して、再度curlしてみたのですが、今度はhttpsリクエストを待ち受けているはずなのにHTTPリクエストが来ているぞ、というエラーが返ってきました。 ingressからpodへのリクエストがHTTPで飛んでしまっていると見当を付け、HTTPSで振り分けるように変更を加えました。
最終的なdiffは以下のとおりです
$ diff ingress.yaml{,.origin} 7,8c7 < nginx.ingress.kubernetes.io/proxy-buffer-size: "16k" < nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" --- > nginx.ingress.kubernetes.io/proxy-buffer-size: "8"
13 サーバ天気予報 (150点)
CORSに関する問題です。
reverse proxy が web.hoge
と api.hoge
に振り分けていて、api.hogeにPOSTすると上手く行かない、みたいな問題だったと記憶しています。
apiサーバはExpressで記述されていました。
VNCで接続したPCのブラウザからweb.hoge
にアクセスしてみたところ、OPTIONS
とPOST
でエラーを吐いていそうです。
3点変更を加えました。
- リバースプロキシ側のnginxのAccess-Control-Allow-MethodsにPOSTを加える
- リバースプロキシのnginxからAccess-Control-Allow-Origin を削除し、api側で
app.use(cors())
を有効化する - api側でOPTIONSリクエストを捌くようにする
diffは以下のとおりです。(この辺からメモが雑になる)
user@proxy-server$ diff /etc/nginx/nginx.conf{,.bk} 79c79,80 < add_header Access-Control-Allow-Methods 'GET,POST'; --- > add_header Access-Control-Allow-Origin '*'; > add_header Access-Control-Allow-Methods 'GET';
user@api-server$ diff /srv/api/server.js{,.bk} 6c6 < app.use(cors()); --- > //app.use(cors()); 16,20d15 < < app.options('/', (req, res) => { < res.status(204); < }); <
以下のファイルの変更を適用し、それぞれサーバとサービスを立ち上げると上手く行くことが確認できました。 (が、これも「なんか動いたからヨシ!」って感じになっています...)
後はapiサーバを永続化させろということだったので、適当にサービスを作ります。
$ sudo cat <<EOF | sudo tee /etc/systemd/system/ictsc-api.service [Unit] Description=ictsc2021-api After= [Service] WorkingDirectory=/srv/api User=user Group=user ExecStart=/usr/bin/npm start ExecStop=/bin/kill -s QUIT \$MAINPID Restart = always Type = simple [Install] WantedBy=multi-user.target EOF
$ sudo systemctl daemon-reload $ sudo systemctl enable ictsc-api.service $ sudo systemctl start ictsc-api.service $ sudo systemctl status ictsc-api.service ● ictsc-api.service - ictsc2021-api Loaded: loaded (/etc/systemd/system/ictsc-api.service; enabled; vendor preset: enabled) Active: active (running) since Sat 2021-08-28 14:53:54 JST; 17s ago Main PID: 1665 (npm) Tasks: 19 (limit: 1108) Memory: 41.1M CGroup: /system.slice/ictsc-api.service ├─1665 npm ├─1686 sh -c node server.js └─1687 node server.js Aug 28 14:53:54 api-server systemd[1]: Started ictsc2021-api. Aug 28 14:53:55 api-server npm[1665]: > api@1.0.0 start /srv/api Aug 28 14:53:55 api-server npm[1665]: > node server.js Aug 28 14:53:55 api-server npm[1687]: server is listening on port 3000...
多分立ち上がっているのでOKです。
14 Webサーバが立ち上がらない(50点)
flaskが使われているプログラムを立ち上げようとすると、 どうやら以前は正常にプログラムが立ち上がっていたらしいのですが、pyenvを導入したことで立ち上がらなくなったようです。
多分pathが変わったのでは?と予想を立てたのですが、まあ強引にpip
で入れて動かしました
$ pip3 install flask $ python3 app/index.py & * Serving Flask app 'index' (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: off * Running on all addresses. WARNING: This is a development server. Do not use it in a production deployment. * Running on http://192.168.7.1:5000/ (Press CTRL+C to quit) $ curl 192.168.7.1:5000 192.168.7.1 - - [28/Aug/2021 10:13:13] "GET / HTTP/1.1" 200 - Hello Flask
OKっぽいです。
15 ンジンエックス(150点)
curl --http2 localhost
でリクエストを送ったら200レスポンスが返ってくるようにせよ、という問題だった気がします。
以下のようにしてnginxを起動しようとするととエラーが出ました。 どうやらhttp2に関するモジュールが存在していないようです。
$ sudo /usr/local/nginx/sbin/nginx nginx: [emerg] the "http2" parameter requires ngx_http_v2_module in /usr/local/nginx/conf/nginx.conf:36 $ sudo /usr/local/nginx/sbin/nginx -V nginx version: nginx/1.21.1 built by gcc 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04) configure arguments: --with-debug # configure arguments: --prefix=/usr/share/nginx (中略) --with-http_v2_module (後略)となっていないため、サポートされていない
普段ならaptとかで入れ直す、みたいなことが出来ると思うんですが、今回はセキュリティ的な制約でファイルをダウンロードしてはいけない、といった制約があったと記憶しています(もしかしたらもっとマイルドな感じの制約だったかもしれません) nginxのモジュールを導入するにはコンパイルが多分必要だと思うのですが、ファイルをダウンロードしないことにはコンパイルできなさそうだなと考えてしまいました。 (多分想定解はnginxをコンパイルし直すことだったのだろうと思います。そのソースをVM上から探し当てることができませんでした)
そのため、以下のように/usr/local/nginx/conf/nginx.conf
に変更を加えてお茶を濁しました。(何も解決していない感がすごいですが...)
diff conf/nginx.conf{,.bk} 36c36 < listen 80; --- > listen 443 http2;
$ sudo /usr/local/nginx/sbin/nginx $ curl --http2 localhost <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
感想
昨年度はほとんど問題で解答にたどり着くことができなかったのですが、今回は沢山問題を解けた気がするので成長を感じました。
非常に教育的に感じる問題も多く、わからない問題を手探りでググりながら学んでいくことができ、色々なことを学ぶ良い機会になったと思います。 非常に楽しいイベントでした。 運営に携わった方々には本当に感謝しています。
いくつかの問題で、想定解と異なる解答をしたり、あるいはよくわからないけど動いている、みたいな状態で提出したりしてしまった部分があったので、改めて勉強し直す必要があるなと感じました。
ただ、久しぶりに長期間集中して作業することになったので、非常に目が疲れました... まずはゆっくり休もうと思います...