hoge な blog

メモとかtipsとか

ICTSC2021 夏の陣に参加しました

はじめに

icttoracon.net

2021年08月の28(土), 29(日)で開催された ICTトラブルシューティングコンテスト2021 夏の陣(ICTSC2021 Summer) に参加しました。

チーム名は「add忘れ VLAN全消し 疎通なし」です。 本番は自分含め3人で参加しました。

(2021/08/30追記) 全体4位でした。入賞圏内だったと思うので、悔しいですね... ただ、本番終了のタイミングでは6位だったのですが、最後にチームメイトが提出した解答が部分点を貰うことができたようで4位に上がることができたようです。 チームの皆さんありがとうございました🙇

f:id:AkkyOrz:20210830215902p:plain
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つの手順で解決しました。

  1. isc-dhcp-server6が動いていなかったので、configを書いて立ち上げる
  2. RAも広告したいので、radvd を立ち上げる
  3. 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.confhost:で指定されている部分を以下のように書き換えます。

#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.hogeapi.hoge に振り分けていて、api.hogeにPOSTすると上手く行かない、みたいな問題だったと記憶しています。 apiサーバはExpressで記述されていました。

VNCで接続したPCのブラウザからweb.hogeにアクセスしてみたところ、OPTIONSPOSTでエラーを吐いていそうです。

3点変更を加えました。

  1. リバースプロキシ側のnginxのAccess-Control-Allow-MethodsにPOSTを加える
  2. リバースプロキシのnginxからAccess-Control-Allow-Origin を削除し、api側でapp.use(cors())を有効化する
  3. 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>

感想

昨年度はほとんど問題で解答にたどり着くことができなかったのですが、今回は沢山問題を解けた気がするので成長を感じました。

非常に教育的に感じる問題も多く、わからない問題を手探りでググりながら学んでいくことができ、色々なことを学ぶ良い機会になったと思います。 非常に楽しいイベントでした。 運営に携わった方々には本当に感謝しています。

いくつかの問題で、想定解と異なる解答をしたり、あるいはよくわからないけど動いている、みたいな状態で提出したりしてしまった部分があったので、改めて勉強し直す必要があるなと感じました。

ただ、久しぶりに長期間集中して作業することになったので、非常に目が疲れました... まずはゆっくり休もうと思います...