ICTSC2018 一次予選参加者の皆さん、お疲れ様でした。
ICTSC2018 一次予選で出題された各問題の解答と解説記事を公開しました。
各問題の記事へのリンクをこちらに掲載しています。
ICTSC2018参加者の方は復習に、次回以降参加するつもりの方は予習に是非役立ててください!
ICTSC2018 一次予選参加者の皆さん、お疲れ様でした。
ICTSC2018 一次予選で出題された各問題の解答と解説記事を公開しました。
各問題の記事へのリンクをこちらに掲載しています。
ICTSC2018参加者の方は復習に、次回以降参加するつもりの方は予習に是非役立ててください!
LinuxカーネルでXenが動作するアーキテクチャとして最も近いものを答えてください。
Docker, OpenVZと言ったソフトはコンテナ仮想化であり、カーネルを全ての仮想マシンで共有してユーザ空間を隔離する技術です。
VirtualBoxはQemuと同じように、OSの上でソフトウェアを起動し、OSの機能を利用して仮想化を行う技術です。
KVM・Xen・Hyper-Vと言ったソフトは、仮想化とその管理の機能を含めたOS制御全ての機能をカーネルに含めたアーキテクチャです。
このうち、KVMでは管理カーネル上でその他のプログラムが動作しますが、
Xenではdom0と呼ばれる管理用の仮想マシンが作成され、その上でカーネルに対して仮想化サーバーの起動などを命令します。
Hyper-VはXenと同様に、管理を行うための仮想マシンが作成され、その上で管理用のプログラムやGUIが動作しています。
Xenでは、管理用の仮想マシンをDomain-0(dom0)、その他の仮想マシンをDomain-U(domU)と呼び、
Hyper-Vではそれぞれ親パーティション (Root Partition, Parent Partition)、子パーティション (Child Partition)と呼びます。
調べればわかる問題ということもあり、問題の正答率は高かったです。
誤答を見ると、同じLinux OS上で動作するということからか「KVM」を選択するチームも見られました。
仮想化を扱う際にはその仮想化の動作原理を知るとトラブルシューティングの際に便利なことがあります。
Xenのトラブルシューティングを行う際に見るべきファイル・実行するべきコマンドを箇条書きで答えよ。
なおこの問題はファイル・コマンドの出力結果から見ることの出来る情報の種類や重要度により点数が増減する。
Xenでは、ログファイルを /var/log/xen
に保存しています。
また、Xenの管理を行うプログラムに xm
(以前のバージョンは xl
)があります。
Xenのシステムのトラブルシューティングはこれらのファイル・コマンドで充分に行えます。
またその他にも /var/lib/xen/
, /var/xen/dump/
に内部で生成されるダンプやデータベースが、
/etc/xen
に設定ファイルが、
/proc/xen
でXenのカーネル情報が取得できます。
参考: 第32章 Xen para-virtualized ドライバーのトラブルシューティング – Red Hat Customer Portal
その他、この問題では言及していないものとして、現在稼働中の物を確認するためのコマンドとしてのxentop
や
libvirtを使用している場合はそれに関連するディレクトリ、
ネットワークに関連するトラブルとしては ネットワークのパケットキャプチャなど、仮想マシンのトラブルシューティングでは見るべき部分が多数あります。
今回の問題はXen本体のトラブルを解決するために必要なファイル・コマンド群双方に言及している場合に最高点数を付与しています。
ファイルのみ・コマンドのみの場合は取得できる情報から30%〜70%で付与しています。
その他のトラブルについて解決するためのコマンド類を記述しているチームには、問題の最高点を上限として加点をしています。
問題文と自由記述の欄から、回答に苦労したチームが多かったのではと思います。
問題文に「見るべきファイル・実行するべきコマンド」と明記しており、ファイルとコマンド双方を回答してくれることを想定していたのですが、コマンドのみ・ログファイルのディレクトリのみの回答も複数ありました。
中には20以上のファイル・コマンドを回答として提出したチームもありました。
情報の中からトラブルの原因を見つけ出し解決に漕ぎ着ける為に、トラブルごとに見るべき項目は異なります。
その際に「どの情報が必要か」を考え、その時々で適切なコマンドの実行・ファイルの閲覧を行うことが大切です。
この時に「どのコマンドで何が取得できる」という事を知っておく事はプラスになります。
Xenの仮想化方式にPVとHVMがありますが、それぞれの違いについて説明してください。
まずPVですが、これはCPUの機能である仮想化支援がなくてもVMを動作させることができる方式です。ただし、VMを動作させるにはPVに対応するドライバが必要なので、そのドライバを別途インストールする必要があります。また、Xenに対応したゲストOSを用いることで、ハードウェアを触らずに高速動作しますが、メモリマッピングといった直接ハードウェアを触る部分で遅延が発生する欠点があります。
HVMはPVと違い、使用するCPUに仮想化支援の機能が必要です(intelならVT-x, AMDならAMD-V)。HVMはqemuを使用してBIOSや様々なコントローラをエミュレートするため、PVのように専用ドライバをインストールする必要がありません。仮想化支援の機能を使うのでハードウェアを触る処理が高速に行える特徴を持ちます。
XenはAmazonが運営しているAWSに採用されています。そのためか、解答にAWS特有の名称などを用いて説明しているチームが複数ありました。
全体的に見てしっかりと説明しているチームが多かったなと思います。
PVとHVMを組み合わせたPVHがりますが、この仮想化方式についてPVとHVMを使って説明してください。
3問目の解説にもある通り、PVはXenに対応したゲストOSを用いることで、ハードウェアを触らずに高速動作しますが、メモリマッピングといった直接ハードウェアを触る部分で遅延が発生します。PVの欠点であるハードウェアを触る処理を、HVMで使われている仮想化支援の機能を使って高速にできるのがPVHとなります。
3問目より4問目の方が回答率が高かったです。
上記のトポロジー図の通りに配線してある機材に設定を投入しましたが、Router-Bから対外への疎通が取れません。
そのため、Router-Bから対外疎通がとれるようにしたいと考えています。
Router-AにGigabitEthernet1側が外部ネットワーク、
GigabitEthernet2側が内部ネットワークとなるようにNATの設定を書き加え、
Router-Bからインターネット(例えばIPアドレス8.8.8.8)へpingを飛ばせるようにしてください。
pingを飛ばす際、経路はRouter-Aを経由します。
Router-AでIPアドレスの設定変更をする必要はありません。
解答メールを送る際は、
・参加者が設定したコンフィグ
・Router-Bからのpingコマンド実行結果
を添えて下さい。
Router-AにNATの設定を書き加え、Router-BからRouter-Aを経由してインターネットにpingを飛ばせるようにする。
Router-Bから、Router-Aを経由して対外接続がはかれない。
今回はCiscoのルータにNATの設定を書き加えてもらう問題でした。
Router-Bは、Router-AにNATの設定を施すことによって対外疎通が可能になります。
こちらの解説では、当初想定していた回答とよく見られた別解を説明します。
まず、当初想定していたNAPT(PAT)の説明をします。
NAPTの設定をする際はまずNAPT変換対象とする送信元IPアドレスをAccess-listで定義する必要があります。
access-list 1 permit any
例えば上記のように設定すると、全ての送信元IPアドレスを許可します。
続いて先程定義したAccess-listと外部インターフェースを関連付けさせます。
ip nat inside source list 1 interface GigabitEthernet1 overload
最後にどのインターフェースを「内部ネットワーク」または「外部ネットワーク」に指定するのか定義します。
ip nat outside
ip nat inside
続いてよく見られた別解であるスタティックNATを説明します。
NAT変換する 「 内部ローカルアドレス 」 と 「 内部グローバルアドレス 」を定義します。
ip nat inside source static 10.0.0.100 192.168.0.100
上記では最も多かった192.168.0.100を内部グローバルアドレスとして定義しています。
最後にどのインターフェースを「内部ネットワーク」または「外部ネットワーク」に指定するのか定義します。
ip nat outside
ip nat inside
なお、Poolを用いたNATやNAPTで設定していても正答となります。
NAPT(PAT)の場合
!Router-A ! enable ! configure terminal ! ! access-list 1 permit any ip nat inside source list 1 interface GigabitEthernet1 overload ! ! interface GigabitEthernet1 ip nat outside ! exit ! interface GigabitEthernet2 ip nat inside !
[別解]スタティックNATの場合
!Router-A ! enable ! configure terminal ! ! ip nat inside source static 10.0.0.100 192.168.0.100 ! ! interface GigabitEthernet1 ip nat outside ! exit ! interface GigabitEthernet2 ip nat inside !
こちらはトラブルを解決するのではなく、参加者に一部だけ構築してもらう問題でした。そのためか回答結果がチームによってさまざまでとても面白かったです。回答を提出してくださったチームのうち、正答であるチームは多かったです。
Kubernetes クラスタ環境を移行後、Kubernetes上のWordPressにアクセスできなくなりました。
原因をつきとめ、修正してください。
Kubernetesクラスタの移行手順書は存在しません。アドレスレンジに以下の変更があったことのみ分かっています。
Address Range: 172.16.0.0/24
-> 192.168.0.0/24
Cluster Address Range: 192.168.0.0/24
-> 10.254.0.0/24
VNC 踏み台サーバ上のブラウザにて「192.168.0.1:30080」を入力することで、WordPressの画面が表示される
Kubernetes Pod の名前解決に失敗するため、wordpress Pod のセットアップに失敗する。その結果、外部からWordPressへのhttpアクセスに失敗する。
当問題の環境では、kube-apiserver が掴んでいる証明書の Subject Alternative Names (SANs) が誤っていることが原因で、Pod からsvc/kubernetesへhttpsでの通信が失敗します。そのため svc/kubernetes との通信が必要である kube-dns Pod を正常に動作させることが出来ず、wordpress Pod から mysql.default.svc.cluster.local:3306
への通信における名前解決に失敗するため、wordpress Pod のセットアップに失敗するという問題が生じます。
当問題は、kube-apiserver が正常な SANs を持つ証明書を掴むよう、証明書を再生成することで解決します。
なおKubernetesは、kube-apiserverの --tls-cert-file
オプションにサーバ証明書、 --tls-private-key-file
オプションに秘密鍵、kube-controller-managerの --root-ca-file
オプションにCA証明書を指定することで Podからsvc/kubernetesへのhttps通信が可能となります。
まず、現在のPodの稼働状況を確認します。
# kubectl get pod NAME READY STATUS RESTARTS AGE mysql-755f57f594-mc9cr 1/1 Running 1 2h wordpress-dc9bb949d-9glcx 1/1 Running 4 2h wordpress-dc9bb949d-sntj9 1/1 Running 4 2h
アクセス先のPodである pod/wordpress のログを確認します。
# kubectl logs wordpress-dc9bb949d-9glcx WordPress not found in /var/www/html - copying now... Complete! WordPress has been successfully copied to /var/www/html Warning: mysqli::__construct(): php_network_getaddresses: getaddrinfo failed: Temporary failure in name resolution in Standard input code on line 22 Warning: mysqli::__construct(): (HY000/2002): php_network_getaddresses: getaddrinfo failed: Temporary failure in name resolution in Standard input code on line 22 MySQL Connection Error: (2002) php_network_getaddresses: getaddrinfo failed: Temporary failure in name resolution ... (省略)
以上のログより名前解決に失敗していることがわかります。/root/manifests/wordpress/deployment-wordpress.yaml
の中身を見ると、WORDPRESS_DB_HOST
環境変数に mysql.default.svc.cluster.local
というドメイン名が渡されているため、当箇所における名前解決に失敗しているものであると考えられます。
Kubernetesクラスタ内のServiceリソースの名前解決は kube-system
ネームスペース内の kube-dns Pod が行います。
kube-dns Pod の稼働状況を確認します。
# kubectl get pod -n kube-system NAME READY STATUS RESTARTS AGE kube-dns-7c7877989-8frxc 2/3 Running 1 1m
kube-dns Pod のログを確認します。
# kubectl -n kube-system logs kube-dns-7c7877989-8frxc kubedns ...(省略) E0729 13:29:49.132142 1 reflector.go:201] k8s.io/dns/pkg/dns/dns.go:192: Failed to list *v1.Service: Get https://10.254.0.1:443/api/v1/services?resourceVersion=0: x509: certificate is valid for 172.16.0.1, 192.168.0.1, not 10.254.0.1 E0729 13:29:49.139524 1 reflector.go:201] k8s.io/dns/pkg/dns/dns.go:189: Failed to list *v1.Endpoints: Get https://10.254.0.1:443/api/v1/endpoints?resourceVersion=0: x509: certificate is valid for 172.16.0.1, 192.168.0.1, not 10.254.0.1 ...(省略)
以上のエラーログより、kube-apiserverの持つ証明書のSANsに10.254.0.1が存在しないことがわかります。
サーバ証明書に対応する秘密鍵である /etc/pki/tls/kube01/server.key
を用いてCSRファイルを再生成します。以下はopensslを用いた例です。
# cat << 'EOF' > /etc/pki/tls/kube01/csr.conf [ req ] default_bits = 2048 prompt = no default_md = sha256 req_extensions = req_ext distinguished_name = dn [ dn ] C = JP ST = dummy L = dummy O = dummy OU = dummy CN = dummy [ req_ext ] subjectAltName = @alt_names [ alt_names ] DNS.1 = kubernetes DNS.2 = kubernetes.default DNS.3 = kubernetes.default.svc DNS.4 = kubernetes.default.svc.cluster DNS.5 = kubernetes.default.svc.cluster.local DNS.6 = kube01 IP.1 = 192.168.0.1 IP.2 = 10.254.0.1 [ v3_ext ] authorityKeyIdentifier=keyid,issuer:always basicConstraints=CA:FALSE keyUsage=keyEncipherment,dataEncipherment extendedKeyUsage=serverAuth,clientAuth [email protected]_names EOF
# openssl req -new -key server.key -out server.csr -config csr.conf
CSRファイルに対し、CA証明書である/etc/pki/tls/kube01/ca.crt
にて署名を行うことでCRTファイルを生成します。
# openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \ -CAcreateserial -out server.crt -days 10000 \ -extensions v3_ext -extfile csr.conf
kube-apiserver.service を再起動します。
# systemctl restart kube-apiserver.service
Pod を明示的に再起動させるため、Pod を再作成します。
# kubectl delete -f /root/manifests/kube-dns/kube-dns.yml &amp;amp;&amp;amp; kubectl create -f /root/manifests/kube-dns/kube-dns.yml # kubectl delete -f /root/manifests/wordpress/wordpress.yaml &amp;amp;&amp;amp; kubectl create -f /root/manifests/wordpress/wordpress.yaml
Kubernetesは利用者が簡単にコンテナのオーケストレーションを行える反面、内部の仕組みは複雑なものになっています。そのためKubernetesについて学ぶ際は、GCP などのクラウドサービスにてKuberntesを利用する他、Kubernetesを実際に構築してみることに是非チャレンジすると良いと思います!
Router1とRouter2は最近、EBGPピアを張ることを決定しました。Router1に設定を行い、Router2とEBGPピアを張ってください。EBGPピアを張ることができたかどうかは、「show ip bgp summary」で確認できます。
なお、以下の注意事項に沿って設定してください。
・ 設定できるルータはRouter1のみです。
・ Router1のAS番号は「1」で設定してください。
・ Router1のebgp neighborを張る宛先はRouter2のLoopbackを指定してください。
この問題のトポロジー図は以下になります。
「sh ip bgp summary」の結果の一番下の行の右端が「0」になっていれば、ピアを張ることができています。
実行例を以下に記載します。この結果では下の行の右端が「0」になっています。
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd 2.2.2.2 4 2 6 8 1 0 0 00:03:39 0
Router1とRouter2間のEBGPピアの設定を行なっていない状態。
Router1とRouter2間でEBGPピアが張ることが出来ている。
neighborやremote-asの設定だけでLoopback間のEBGPピアを張ることができない。
Router1からRouter2にEBGPピアを張るには、BGP Neighborの設定が必要です。
今回の問題ではCisco機材を使用しているため、Cisco用のコマンドによる設定になります。
具体的には以下のような設定が必要になります。
enable configure terminal router bgp 1 neighbor 2.2.2.2 remote-as 2
ですが、これだけではEBGPピアを確立させることはできません。
本来、EBGPピアは、実際に接続されているインターフェース間で行われることが一般的で、
追加の設定をしない限りは、それを前提にピアを張ろうとします。
しかし、今回の問題では、Loopbackインターフェース同士でピアを張る必要があるため、
追加の設定が必要になります。具体的な設定は以下になります。
ip route 2.2.2.2 255.255.255.255 192.168.1.2 neighbor 2.2.2.2 update-source loopback 0 neighbor 2.2.2.2 ebgp-multihop
3つの設定をBGPの設定に加えることで、Loopbackインターフェース間でEBGPピアを張ることができるようになります。
上から、説明していきます。
ip route 2.2.2.2 255.255.255.255 192.168.1.2
これは、Router1がRouter2のLoopbackのアドレスを知らないから疎通性がないことを解消するための設定です。ピアを張る際は、そのインターフェースと疎通性が取れないと張ることができないからです。
neighbor 2.2.2.2 update-source loopback 0
BGPメッセージを送る際の送信元をRouter1 のLoopback 0に指定します。デフォルトでは、送信元はRouter1の物理インターフェースに指定されているため、送信元を変える必要があります。
neighbor 2.2.2.2 ebgp-multihop
EBGPでピアを張る際のBGPのメッセージのTTL(Time to live)の数を増やすために設定します。
EBGPピアを張る際のBGPメッセージのTTLはデフォルトで「1」に設定されているため、Loopbackインターフェース間だとTTLが足りなくパケットロスが起きてしまいます。なお、「ebgp-multihop」の後に引数を指定しないと「255」になります。
以上の設定を踏まえて、最終的な解答コンフィグを以下に記載します。
!Router-A ! enable ! configure terminal ! ip route 2.2.2.2 255.255.255.255 192.168.1.2 ! router bgp 1 neighbor 2.2.2.2 remote-as 2 neighbor 2.2.2.2 update-source loopback 0 neighbor 2.2.2.2 ebgp-multihop !
この問題はBGPでルーティングを行う際に、最初に行うEBGPピアを張ってもらう問題でした。
Loopbackインターフェースを用いることを前提に設定を組んでいたチームが半分を超えていて、出題してよかったと思います。
EBPGピアを張る際に、Loopbackを用いることもできることを知っていただけたら幸いです。