はじめに
icttoracon.net
2021年08月の28(土), 29(日)で開催された ICTトラブルシューティング コンテスト2021 夏の陣(ICTSC2021 Summer) に参加しました。
チーム名は「add忘れ VLAN全消し 疎通なし」です。
本番は自分含め3人で参加しました。
(2021/08/30追記)
全体4位でした。入賞圏内だったと思うので、悔しいですね...
ただ、本番終了のタイミングでは6位だったのですが、最後にチームメイトが提出した解答が部分点を貰うことができたようで4位に上がることができたようです。
チームの皆さんありがとうございました🙇
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>
感想
昨年度はほとんど問題で解答にたどり着くことができなかったのですが、今回は沢山問題を解けた気がするので成長を感じました。
非常に教育的に感じる問題も多く、わからない問題を手探りでググりながら学んでいくことができ、色々なことを学ぶ良い機会になったと思います。
非常に楽しいイベントでした。
運営に携わった方々には本当に感謝しています。
いくつかの問題で、想定解と異なる解答をしたり、あるいはよくわからないけど動いている、みたいな状態で提出したりしてしまった部分があったので、改めて勉強し直す必要があるなと感じました。
ただ、久しぶりに長期間集中して作業することになったので、非常に目が疲れました...
まずはゆっくり休もうと思います...