ICTSC2020予選を通過したおはなし
はじめに
2020年10月31日にICTSC2020の予選にLynT4χ(リンタッカイ)として参加させていただきました。 これまでもICTSCには何度か弊学メンバーで出場していましたが、今年が最期だろうということで、メンバー3人(うち1人は予選欠席:fearful:)で記念受コンしました。 結果としては、40チーム中6位で、まずまずかなと思います。
今回も備忘録として、今回ぼくが解いた問題のwriteup(回答)を残しておきます。 問題文などは、ちゃんと保存していないので、公式の解説ページから頂戴いたしました。
ルーティング
networkが作成できない?(100/100)
dockerのネットワークについてはあまり意識して見たことがなかったので、勉強になりました。
問題
docker-composeを使って,NetBoxを運用していました. 運用サーバに新しくインターフェースを追加したところ,NetBoxがうまく起動できなくなりました. 原因を調査して,修復してください.
回答
この問題では、新たに追加されたIPv4インターフェースが、dockerにて利用されるdefaultネットワークのIPv4アドレス空間を専有してしまっていたために、トラブルが発生したと考えられます。
そのため、以下のように設定を変更し、正常にdocker-compose up
ができることを確認いたしました。
ご確認のほど、よろしくお願いいたします。
手順
1: ~/netbox-docker/docker-compose.yml
の最終行以下に, 次の設定を追加
networks: default: ipam: config: - subnet: 192.168.1.0/24
2: docker-composeコマンドにより、NetBoxが正常に起動できることを確認
user@app0:~/netbox-docker$ sudo docker-compose up -d Starting netboxdocker_redis_1 ... Starting netboxdocker_postgres_1 ... Starting netboxdocker_redis_1 Starting netboxdocker_redis-cache_1 ... Starting netboxdocker_postgres_1 Starting netboxdocker_redis_1 ... done Starting netboxdocker_netbox-worker_1 ... Starting netboxdocker_postgres_1 ... done Starting netboxdocker_netbox_1 ... Starting netboxdocker_netbox_1 ... done Starting netboxdocker_nginx_1 ... Starting netboxdocker_nginx_1 ... done
参考
- Docker “ERROR: could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network” | stackoverflow
- Dockerはネットワークを31個しか作れない - ashphy's commit logs
またビルド失敗しちゃった〜...(100/100)
Goはほとんど触ったことがなかったので、不安でしたが、なんとなくggってくと回答が見えてきたので、なんとか解けました。 ダイナミック/スタティックリンクの同様のトラブルはGo以外でも発生しそうだなあと解きながら思ったので、面白い問題でした。
問題
新入社員の障害太郎くんがGoの勉強をしようとしています。 どうやらDockerのマルチステージビルドを使って、Goのバイナリをコンテナ上で実行しようとしたらうまく立ち上がらないようです。 先輩のトラシュウさんに聞いたところ、「Dockerfileが間違っている」というメモを残して業務に戻ってしまいました。 先輩のトラシュウさんの代わりに原因を特定して修正してあげてください。
回答
この問題では、goのバージョン1.4以降から、デフォルトでビルドしたバイナリファイルがダイナミックリンクになってしまうことが原因で、トラブルが発生していたと考えられます。 バイナリファイルがダイナミックリンクになってしまっていると、別環境(今回の環境ではbuilderイメージではないほうのイメージ)では、バイナリファイルを正常に実行できません。
これを修正する方法として、
1: cgo
を無効にすることで、ダイナミックリンクではなくスタティックリンクのバイナリファイルを生成する
2: go build
の引数に、スタティックリンクとするようなオプションを指定する
- 例: $ go build -a -tags netgo -installsuffix netgo --ldflags '-extldflags "-static"'
の2通りが考えられます。
今回は特に、cgo
を利用しているコードはなかったため、builderイメージに、CGO_ENABLED=0
という環境変数を新たに追加することで、正常にコンテナを起動でき、curl
コマンドで想定のレスポンスが得られることを確認いたしました。
ご確認のほど、よろしくお願いいたします。
手順
1: dockerファイルを次のように書き換え(4行目にCGO_ENABLED
を追加)
FROM golang:1.15.0 AS builder ENV GO111MODULE=on ENV GOPATH= ENV CGO_ENABLED=0 COPY ./server/main.go ./ RUN go mod init ictsc2020 RUN go build -o /app ./main.go FROM alpine:3.12 COPY --from=builder /app . EXPOSE 1323 ENTRYPOINT "./app"
2: dockerコンテナが正常に起動できることを確認
user@server01:~/app$ docker run -p 80:1323 ictsc2020 & [1] 26697 user@server01:~/app$ ____ __ / __/___/ / ___ / _// __/ _ \/ _ \ /___/\__/_//_/\___/ v4.1.17 High performance, minimalist Go web framework https://echo.labstack.com ____________________________________O/_______ O\ ⇨ http server started on [::]:1323
3: curlコマンドで正常なレスポンスが得られることを確認
user@server01:~/app$ curl localhost Welcome to ICTSC2020!
参考
ウェブ
WEBページが見れない(100/100)
途中まで、もうひとりのチームメンバーが解いてくれていた問題を引き継いで解いた問題です。 (SE)Linuxの権限設定って複雑で管理しづらいなあと思った問題でした。
問題
apacheのDocumentRootを/var/www/htmlから/home/user/htmlに変更して、$curl http://127.0.0.1/home.html
を実行したら、403エラーが返ってきてアクセスできない。
回答
この問題では、主に権限の正しい設定が行われていないことが原因で、403エラーが返されるというトラブルが発生していたと考えられます。
そこで、次の手順により、正しい設定を行うことで、curl
コマンドで想定のレスポンスが得られることを確認いたしました。
ご確認のほど、よろしくお願いいたします。
手順
1: /etc/httpd/conf/httpd.conf
に次の設定を追加
<Directory "/home/user/html"> Require all granted </Directory>
2: 新たに指定したDocumentRootディレクトリのコンテキストを元のDocumentRootコンテキストと同様のものに設定
$ ls -ld --context /home/user/html drwxr-xr-x. user user system_u:object_r:user_home_t:s0 /home/user/html $ ls -ld --context /var/www/html drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html $ sudo chcon system_u:object_r:httpd_sys_content_t:s0 /home/user/html -R $ ls -ld --context /home/user/html drwxr-xr-x. user user system_u:object_r:httpd_sys_content_t:s0 /home/user/html
3: /home/user
ディレクトリに実行権限を付与
$ chmod 711 /home/user
4: httpd
サービスをリスタート
$ sudo systemctl restart httpd
5: curl
コマンドで正常にレスポンスが得られることを確認
$ curl http://127.0.0.1/home.html <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Apache Server</title> </head> <body> <div style="text-align: center;"> <h1> Successful Access To Apache Server</h1> </div> </body> </html>
参考
コンテナ
どこからもアクセスできなくなっちゃった(40/200)
この問題では、トラブルの原因をある程度特定できたところで、コンテスト終了に近づいていたので、その部分だけリポートし、部分点を頂きました。
問題
k8sのクラスターを、マスター1台(master)、ワーカー2台(worker01, worker02)、ロードバランサー1台(lb)という構成で構築しました。 ロードバランサーにはHAProxyを用いており、kube-apiserverであるmaster(172.16.0.1:6433)へのプロキシと、各ワーカーの30080のNodePort(172.16.0.11:30080, 172.16.0.12:30080)へのロードバランシング, k8sクラスタの各ノードのデフォルトゲートウェイとしてiptablesを用いたMasqueradeを行っています。
k8sクラスタでは、nginxをreplica 数1つで展開するDeploymentと、それを外部にNodePort 30080で公開するServiceが作成されています。 このnginxに対して外部(external)からの通信においてhost01からのみアクセスできるといったアクセス制限を行うため、NetworkPolicyを用いて制限をかけたところ、host01からもアクセスできなくなってしまいました。
なぜhost01からもアクセスできないのか原因と解決方法、解決でき再起動しても問題のない作業手順を報告してください。
回答
この問題では、ロードバランサーによって接続元IPアドレスが変更されているために、正常にトラフィックのフィルタリングが行えず、トラブルが発生したと考えられます。
実際に、以下のように、nginxのログを確認したところ、接続元IPアドレスが192.168.0.0/24
の空間ではないものになっています。
これを考慮した、設定を行う必要があります。
user@host01:~/manifests$ kubectl logs my-deployment-d46f5678b-b67hs -n my-ns /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/ /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh 10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf 10-listen-on-ipv6-by-default.sh: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh /docker-entrypoint.sh: Configuration complete; ready for start up 172.16.0.12 - - [31/Oct/2020:08:38:32 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.58.0" "-" 172.20.5.0 - - [31/Oct/2020:08:42:41 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.58.0" "-" 172.16.0.12 - - [31/Oct/2020:08:42:55 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.58.0" "-" 172.20.5.0 - - [31/Oct/2020:08:43:00 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.58.0" "-" 172.16.0.12 - - [31/Oct/2020:08:43:20 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.58.0" "-" 172.20.5.0 - - [31/Oct/2020:08:43:22 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.58.0" "-" 172.16.0.12 - - [31/Oct/2020:08:47:35 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.58.0" "-" 172.20.5.0 - - [31/Oct/2020:08:48:02 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.58.0" "-" 172.16.0.12 - - [31/Oct/2020:08:48:14 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.58.0" "-"
ダイエットしようぜ!(100/100)
参考リンクとしても貼りましたが、golang smallest image
とかでggると一番上に該当記事が出てくるので、これを読めば10分ぐらいで解ける問題でした。googling大事。
問題
GoでSHA256するhash.go
を書いた。これを実行するコンテナが欲しかったので雑にDockerfile
を書いてビルドしてイメージを作成した。問題なくSHA256できるようになったが、イメージが大きくてテンションが上がらない。 あなたには、Dockerfile
を編集したりビルドコマンドを変えたり、あるいはビルド後のイメージに対してなにかしたりしてイメージを小さくしてほしい。 ただし、hash.go
のコードにはこだわっているので編集してはならない。 $ make build
でictsc-dit
という名前のDocker imageを作ることができる。詳細はMakefile
を参照されたい。採点の際にVMを確認する場合、どのイメージが回答によって作成されたイメージかすぐに判別できるよう、是非使ってほしい。
回答
この問題では、以下の2つのいずれかを実践することで、Dockerイメージのサイズを減らすことができます。
- ベースとなるgolangのDockerイメージのタグを
alpine
にする - マルチステージビルドを利用する
今回は、よりイメージサイズを減らすことができる、マルチステージビルドを利用しました。
その結果、イメージサイズを2.05MB
まで減らすことができました。
手順
1: Dockerfile
の中身を以下のように書き換え
# step 1 FROM golang:alpine AS builder ADD . /work WORKDIR /work RUN go build -o /go/bin/hash # step 2 FROM scratch COPY --from=builder /go/bin/hash /go/bin/hash ENTRYPOINT ["go/bin/hash"]
2: make build
でイメージをbuild
3: docker images
でイメージサイズを確認
user@vm01:~$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE ictsc-dit latest 7a50b38100f3 5 minutes ago 2.05MB
4: docker run
で正常にコンテナが動作することを確認
user@vm01:~$ make run docker run -it --rm --name ictsc-dit-container ictsc-dit data: aaa SHA256: 9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0
参考
データベース
備品は何処へ(100/100)
ぼくの読解力が悪いのか、問題文と終了状態の定義が曖昧な気がして、それの確認に時間が取られた問題でした。。 普段DBを触るにしてもWeb Frameworkのラッパー経由が多く、SQLをそのまま触る機会は減っていたので、復習しながら取り組めたのでよかったです。
問題
あなたは現在、自社の備品を管理する部署に勤務している。管理システムはとても古くMySQLを利用している。
ある日、上司から特定の製造会社のパソコン(Manufacturing_company_E
)、特定の建物(HQ
)で相性が悪く交換するためリストを作成してほしいと依頼を受ける。なお、注文会社はパソコンの管理を行う専門会社である。
MySQLのデータベースからcsvファイル(submit.csv)を出力するSQL文(submit.sql)を作成し実行しなさい。
回答
- submit.sql
USE List; SELECT Equipment_list.ID AS "Equipment ID" ,Equipment_list.Name AS "Equipment Name" ,Order_company_list.Name AS "Order company Name" ,Manufacturing_company_list.Name AS "Manufacturing company Name" ,Equipment_list.Price AS "Equipment Price" FROM Equipment_list JOIN Manufacturing_company_list ON Equipment_list.Manufacturing_campany=Manufacturing_company_list.id JOIN Order_company_list ON Equipment_list.Order_company=Order_company_list.id JOIN Location_list ON Equipment_list.Use_place=Location_list.id WHERE Manufacturing_company_list.Name='Manufacturing_company_E' AND Location_list.Building_name='HQ' ORDER BY Equipment_list.Price DESC INTO OUTFILE '/tmp/submit.csv' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"';
- submit.csv
24,"pc_x","Order_company_E","Manufacturing_company_E",1600 17,"pc_q","Order_company_J","Manufacturing_company_E",800
おわりに
Dockerはアルバイトでよく使っているので、今回Docker問題が多くてラッキーでした。予選ラッキー通過でした。 k8sは最近さわりはじめたばかりなので、本戦までには太刀打ちできるようになっていてほしいです(To自分)。 今回、ネットワーク問題はほとんど解いておらず、得意かというとそうでもないので、本戦までに頑張っていきたいです。
参加者、運営のみなさんトラブルシューティングお疲れさまでした。