ICTSC2025 一次予選 問題解説: 問32 - 問35

問32

ictsc-app という名前のアプリ開発をDockerコンテナを用いて行っている。開発中、動作確認のために docker run コマンドでアプリケーションを立ち上げたところ、何のエラーメッセージも残さず、すぐに終了してしまった。

このままでは原因の特定が困難であるため、デバッグのために sleep コマンドでコンテナを立ち上げたままにしておいて、手動でアプリケーションの起動を行うことにした。

早速、以下のコマンドを用いてデバッグを行ったところ、想定とは異なり、何のエラーメッセージも残さず、すぐにコンテナが終了してしまった。

$ docker run ictsc-app sleep infinity
<何のエラーも表示されない>
$ 

参考として、ictsc-app のイメージの inspect 結果を以下に記載する。

[
    {
        "Id": "sha256:fbf43b316565127503a3dfd8b91555ee90b8e0c45253b6c662bfba0980d67d7b",
        "RepoTags": [
            "ictsc-app:latest"
        ],
        "RepoDigests": [],
        "Parent": "",
        "Comment": "buildkit.dockerfile.v0",
        "Created": "2025-07-20T12:36:39.693337178Z",
        "DockerVersion": "",
        "Author": "",
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 228891807,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/zkni6b0f322qj7fbxf6vuqbl8/diff:/var/lib/docker/overlay2/evianeisobabny0hal63mfxkz/diff:/var/lib/docker/overlay2/v77bsu7awo1rc0g9jzee6a2ay/diff:/var/lib/docker/overlay2/xrw3obhyses63qxii0d16wz0n/diff:/var/lib/docker/overlay2/f16r4zgulg80u238s6jt4qllc/diff:/var/lib/docker/overlay2/a75173256e30d32a5924d904e3374f744a9b963330f3d03a07c507f6f4fbc7db/diff:/var/lib/docker/overlay2/67c6bcfeecdf156a1846805cffa104cd1638abd9c3cc0719977799f5cfc3c7c3/diff:/var/lib/docker/overlay2/b24eab56679a9d8d52fe510a171d2f0ff6722f8ebb8816fa87bfca0adec04f15/diff:/var/lib/docker/overlay2/9e5ff3b7938c82f17e782093a275b1d27ef5357fd5543a73e07e87727eb7e914/diff:/var/lib/docker/overlay2/700e9b1d337627e508de8474fd308b441c697c9cff16f74f4fe9b0b0950f4f85/diff",
                "MergedDir": "/var/lib/docker/overlay2/xw56bqt5n6mpbt9rwaivv76m4/merged",
                "UpperDir": "/var/lib/docker/overlay2/xw56bqt5n6mpbt9rwaivv76m4/diff",
                "WorkDir": "/var/lib/docker/overlay2/xw56bqt5n6mpbt9rwaivv76m4/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:1bb35e8b4de116e84b2ccf614cce4e309b6043bf2cd35543d8394edeaeb587e3",
                "sha256:f812e127e0f9a0d7faa4adbd6e7d873e42ebcff11d259072ae50b6352c974c70",
                "sha256:ffb20e72f4439a0a3cd15016f88ff96b70f32cecce8e2ed9e7301da32930246b",
                "sha256:67d8d621bc8be2ed5ef4e017e4237ebecf2f51e3048537b940cabf4e3c3cfcd2",
                "sha256:f3acd5c28703efcaf432602c2054b6761fc20576320b1e4de0130f9dc485b239",
                "sha256:53349f3b3db7206e7377bf0a02fe93a67004a66b0be4846616fdc8957116a74c",
                "sha256:e7e841982c20b39ccdbd3ee8487abb88c5c00cf5d191442f44d3331c2c6560e0",
                "sha256:2b18ef3e69e1be7619ddbfbbf8cf281d4256bd3d7b02d7401fddf43e9d10d62b",
                "sha256:f59971410f3f5df177c7c0b2e77b46f1db88fd663a1c072f28b909ce44a6922b",
                "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
                "sha256:135a92f6fd34095609ae87227871a54768ab89e08b234dd3b285b85456b5d7a6"
            ]
        },
        "Metadata": {
            "LastTagTime": "2025-07-20T12:36:39.859733108Z"
        },
        "Config": {
            "Cmd": null,
            "Entrypoint": [
                "node",
                "./index.js"
            ],
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NODE_VERSION=22.17.1",
                "YARN_VERSION=1.22.22"
            ],
            "ExposedPorts": {
                "3001/tcp": {}
            },
            "Labels": null,
            "OnBuild": null,
            "User": "",
            "Volumes": null,
            "WorkingDir": "/app"
        }
    }
]

コンテナが終了してしまう原因として最も適当なものを1つ選べ。

選択肢(択一選択)

  1. ictsc-app イメージ内に sleep コマンドが存在しない
  2. sleep コマンドが、コンテナの起動時に実行されるイメージで指定されているコマンドによって上書きされてしまった
  3. sleep コマンドが、コンテナ起動時に実行されるイメージで指定されているコマンドの引数として解釈されてしまった
  4. sleep コマンドがバックグラウンドで実行されてしまった

正解

3

解説

正解は 3 の 「sleep コマンドが、コンテナ起動時に実行されるイメージで指定されているコマンドの引数として解釈されてしまった」
(句点をつけ忘れてしまい、めちゃくちゃ読みづらい選択肢になってしまったことを反省しています)

Docker コンテナの ENTRYPOINTCMD の組み合わせに関して問う問題でした。

  • 「コンテナ起動時に実行されるイメージで指定されているコマンド」= ENTRYPOINT
  • 「コマンドの引数」= CMD

という意味でした。

ENTRYPOINTCMD はコンテナ実行時に実行されるコマンド文字列を指定する命令ですが、両方を同時にしていを指定すると、CMD で指定された文字列は ENTRYPOINT の引数として評価されます。

また、docker run コマンドの引数として指定した文字列(オプション以外。今回の問題で言えば sleep infinity のところ)は CMD として評価されます。

与えられた inspect 結果をよく見てみると、ENTRYPOINT として node ./index.js が渡されているため、docker run sleep infinity を実行すると、コンテナ内部では node ./index.js sleep infinity として実行されます。

sleep コマンドを指定したが、node コマンドの引数として評価されてしまったのでコンテナがすぐに終了してしまったというわけです。

他の選択肢が除外できる理由は以下の通りです

    1. ictsc-app イメージ内に sleep コマンドが存在しない
    • もし sleep コマンドを正しく指定できており、なおかつ sleep コマンドが存在しない場合は、そのようなエラーメッセージが出るはずです。
    1. sleep コマンドが、コンテナの起動時に実行されるイメージで指定されているコマンドによって上書きされてしまった
    • CMD が元々指定されているイメージに、ENTRYPOINT で上書き(正確には、引数としてしまう)することはできますが、逆はできません。
    1. sleep コマンドがバックグラウンドで実行されてしまった
    • バックグラウンド実行を行う指定を一切していないので不適です。
  • 参考: https://docs.docker.jp/v1.12/engine/reference/builder.html#cmd-entrypoint

問33

以下のような構成でローカルネットワークを構築した(この図に記載されているもの以外のサーバやネットワーク機器はない)。

+---------------------------+        +---------------------------+ 
|           Host1           |        |           Host2           |
|                           |        |                           |
| IP(eth1): 192.168.0.1/24  |        | IP(eth1): 192.168.0.2/24  | 
| Nameserver: 192.168.0.254 |        | Nameserver: 192.168.0.10  | 
| Route:                    |        | Route:                    |
|  default via192.168.0.254 |        |  default via192.168.0.254 | 
+---------------------------+        +---------------------------+
             |(eth1)                              |(eth1)
             +------------------+-----------------+
                                |(eth1)
                 +----------------------------+
                  |     Router(Default GW)     |
                  |                            |
                  | IP(eth1): 192.168.0.254/24 |
                  | 提供サービス: DNS Resolver  |
                  +----------------------------+

このネットワーク上で、Host1 から Host2 へ SSH 接続を行ったところ、接続に5秒程度時間がかかった。普段であれば、1秒以内に接続できるのだが、どうやら Host2 の sshd_config を変更した後から、5秒程度かかるようになってしまった。

以下は Host2 の sshd_config である。

# This is the sshd server system-wide configuration file.  See
# sshd_config(5) for more information.

# This sshd was compiled with PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented.  Uncommented options override the
# default value.

Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::

#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key

# Ciphers and keying
#RekeyLimit default none

# Logging
#SyslogFacility AUTH
LogLevel INFO

# Authentication:

#LoginGraceTime 2m
#PermitRootLogin prohibit-password
#StrictModes yes
MaxAuthTries 6
MaxSessions 10

#PubkeyAuthentication yes

# Expect .ssh/authorized_keys2 to be disregarded by default in future.
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2

#AuthorizedPrincipalsFile none

#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody

# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes

# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication no
PermitEmptyPasswords no

# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
KbdInteractiveAuthentication no

# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no

# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no

# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the KbdInteractiveAuthentication and
# PasswordAuthentication.  Depending on your PAM configuration,
# PAM authentication via KbdInteractiveAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and KbdInteractiveAuthentication to 'no'.
UsePAM no

AllowAgentForwarding yes
AllowTcpForwarding yes
GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
UseDNS yes
#PidFile /run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none

# no default banner path
#Banner none

# Allow client to pass locale environment variables
AcceptEnv LANG LC_*

# override default of no subsystems
Subsystem sftp /usr/lib/openssh/sftp-server

# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server

以下の文はこの問題の解決法をを記している。[X] と [Y] を適切な単語で補い文を完成させよ。

sshd_config の [X] の設定を [Y] にし、Host2 の sshd を再起動する

正解

sshd_config の [useDNS] の設定を [no] にし、Host2 の sshd を再起動する

解説

sshduseDNS 設定に関する問題です。

useDNS を有効にすると、SSH 接続時に IP アドレスの逆引きが行われます。

authorized_keysfrom="hostname" のような記述をしておくと、接続元を特定のドメインを持つホストに限定したりできます。

しかし、何らかの理由で SSH 先の DNS サーバ設定がうまく行ってないと、DNS の逆引きでタイムアウトになるまで試行してしまうことがあり、 SSH 接続が遅くなったように感じられることがあります。

今回、ネットワーク構成図をよく見てみると、 Host2 の Nameserver が存在しない IP アドレスを指定しています。
ネットワーク構成図に書かれたもの以外のサーバやネットワーク機器は一切存在しないので、上記のような現象が発生しました。

このトラブル、どうやら昔からよくあるようで、「SSH 遅い」で検索してみると、結構上位に来ています。

問34

以下のような構成の Kubernetes リソースがある。

app1app2 はそれぞれ別々の Nginx Ingress があり、このそれぞれに外部の LB(ロードバランサ) が紐づけられている(ここでいう Nginx Ingress は、kubernetes/ingress-nginx を利用している)。

この外部LBは非常にコストがかかるため、LB を1つにまとめる方針になった。具体的には、app1app2 の Ingress を共通のものとして切り出し、common という namespace にデプロイすることで、1つの LB だけですべてのサービスを公開できるようにしたい。

common.ymlapp1.ymlapp2.yml の三種類のリソースを用意し、実際に検証を行ってみたところエラーが発生してしまった。

以下は common.yml である。

kind: Namespace
apiVersion: v1
metadata:
  name: common
  labels:
    name: common
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
  namespace: common
spec:
  ingressClassName: nginx
  rules:
    - host: app1.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                namespace: app1
                name: app1-service
                port:
                  number: 80
    - host: app2.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                namespace: app2
                name: app2-service
                port:
                  number: 80

以下は app1.yml である。

kind: Namespace
apiVersion: v1
metadata:
  name: app1
  labels:
    name: app1
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app1-deployment
  namespace: app1
  labels:
    app: app1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app1
  template:
    metadata:
      labels:
        app: app1
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: app1-service
  namespace: app1
  labels:
    app: app1
spec:
  selector:
    app: app1
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP

以下は app2.yml である。

kind: Namespace
apiVersion: v1
metadata:
  name: app2
  labels:
    name: app2
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app2-deployment
  namespace: app2
  labels:
    app: app2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app2
  template:
    metadata:
      labels:
        app: app2
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: app2-service
  namespace: app2
  labels:
    app: app2
spec:
  selector:
    app: app2
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP

以下は実行したコマンドと発生したエラーである。

$ kubectl apply -f common.yml
Error from server (BadRequest): error when creating "common.yml": Ingress in version "v1" cannot be handled as a Ingress: strict decoding error: unknown field "spec.rules[0].http.paths[0].backend.service.namespace"

このエラーが発生している原因を記述せよ。
また、どのように YAML ファイルを変更すれば変更後の構成通り1つの LB で app1app2 を公開できるか、YAML の差分を記述せよ。

なお、以下の点に注意すること。

  • 既存のリソースを変更する際は、YAML ファイル名と、どのリソース、キーをどのように変更したか記述する
  • 例:
    • 変更対象: app1.yml の Service (metadata.name: app1-service)
      • 変更内容:
        • metadata.labels.appapp1 から app1-hoge に変更
        • spec.ports[0].protocolTCP から UDP に変更
  • 新規リソースを作成する際は、追記するファイル名と、新規リソースの定義を記述する
  • common namespace のリソース以外は変更してはならない
  • app1app2 は別チームが開発しており、変更の権限がない
  • カスタムリソースは使用できない
  • Ingress の annotation を変更(追加、削除、編集)してはならない

なお、Kubernetes クラスタの基本情報を以下に示す。

  • Kubernetes Version: v1.33.1
  • Cluster Domain: cluster.local

正解

模範解答:
エラーの原因は、Ingress リソースの backend servic eには、namespace を指定できないことにある。

解決策としては、common namespace にある Service を、ExternalName Service に変更し、app1app2 それぞれにある Service の FQDN を指定する。

  • 変更対象: common.ymlService (metadata.name: app1-service)
    • 変更内容:
      • spec.typeExternalName とする
      • spec.externalName を追加し、Value を app1-service.app1.svc.cluster.local とする
  • 変更対象: common.ymlService (metadata.name: app2-service)
    • 変更内容:
      • spec.typeExternalName とする
      • spec.externalName を追加し、Value を app2-service.app2.svc.cluster.local とする

以下は想定する common.yml である。

kind: Namespace
apiVersion: v1
metadata:
  name: common
  labels:
    name: common
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-ingress
  namespace: common
spec:
  ingressClassName: nginx
  rules:
    - host: app1.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: app1-service
                port:
                  number: 80
    - host: app2.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: app2-service
                port:
                  number: 80
---
apiVersion: v1
kind: Service
metadata:
  name: app1-service
  namespace: common
spec:
  type: ExternalName
  externalName: app1-service.app1.svc.cluster.local
---
apiVersion: v1
kind: Service
metadata:
  name: app2-service
  namespace: common
spec:
  type: ExternalName
  externalName: app2-service.app2.svc.cluster.local

解説

Ingress リソースを使って何とか LB を一つにできないかという問題です。
AWS で EKS を使っていたりすると、1つの Ingress に対して 1つの ALB が立ち上がっており、思ったより料金がかかっていた...というあるある(?)です。開発環境だと環境が増えまくるので、気を付けなければいけないポイントだと思います。

まず、エラーが発生してしまっていた理由ですが、エラーメッセージの通り、Ingress (Kubernetes v1.33) リソースには、spec.rules[0].http.paths[0].backend.service.namespace のように、service に対して namespace を指定することはできません。

つまり、Ingress リソース単体では、別 namespace のリソースを参照できないのです。

様々な方法で回避ができますが、今回は ExternalName Service を想定して作問してみました。

ExternalName Service は、Service を特定ドメインにマッピングしてくれます。

例えば、example.com というドメインを example という名前の Service にマッピングできます。内部的には、example Service の FQDN を、example.com の CNAME として登録することで実現しています。

さて、この ExternalName を app1app2 namespace にある Service を参照するために使ってみましょう。

Service リソースには、 FQDN が割り当てられており、これは他の namespace からも名前解決ができます。
そこで、common namespace に、app1app1-serviceapp2app2-service を参照する ExternalName Service を使えば、他の namespace の Service も参照できるようになるというわけです。

採点基準

今回は、採点基準を作るのにかなり苦戦しました。というのも、解答のバリエーションが様々だったからです。

この問題は12点問題で、大まかな方針としては、

  • 原因を正しく指摘できていれば6点
  • YAMLファイルの差分を正しく記述できていれば6点

としました。

また、ExternalName Service を使わない解答もすべてローカル環境で動作確認をし、方針として問題が無ければ正答としています(満点でない場合は、タイポ等の細かいミスで減点している可能性が高いです)

模範解答以外の方針としては、以下のようなものがありました

  • common namespace に nginx deployment, Service を置いて、app1,2 の Service に対して proxy する
  • app1-service の IP を参照する Entrypoints リソースを作成し、common リソースにそれを参照する Service を置く

その他、細かい基準に関しては以下に書いておきます。

- 原因を正しく指摘できている(namespaceを指定してしまっている): 6点
  - 原因を書き忘れているが、問題を解決できている場合は3点
- YAMLファイルの差分を正しく記述できている: 6点
  - 正しく記述できているの基準
    - type:ExternalService を指定したサービスを作れている: 6点
      - YAMLや差分の記述等からExternalServiceを作ろうとしていることが分かれば2点
      - ExternalService のフォーマットに従っている
        - type: ExternalService で1点
        - externalName で1点
      - パラメータミス(綴りミス等ではなく不足など)の場合は2点マイナス
  - その他
    - 単純なtypoなら1点マイナス
      - インデント誤りはtypoとしない
    - 問題文に指定されていた差分を記述していない場合(変更後だけを載せている場合)などは2点減点
    - namespace の指定を削除しただけでは0点(問題文に、ゴールがLB1台でサービスを公開できていることと指定されているので)
    - port などを指定している場合は特に減点なし
      - ExternalName タイプのサービスは、DNS の CNAME として機能するため、ポートを指定しても動作に何も影響がない。(80番ポート以外を指定してもOK)

- その他の解法は、動作確認の上、下記基準で採点しています
  - 問題の構成をきちんと再現できている: 6点
    - kubectl applyコマンドでデプロイができない(YAML形式ミス、バリデーションエラー等)場合は2点マイナス
    - パラメータミス(サービス名の指定ミス)などが1,2カ所程度あれば2点マイナス
  - 再現できない場合も、大まかな方針が合っていれば2点

問35

メール認証技術について、間違っているものを全て選べ。

選択肢(複数選択)

  1. SPF と DKIM の両方が成功すれば、DMARC 認証は必ず成功する
  2. DMRAC 認証が失敗し、p=reject の場合は、メールは常に届かない
  3. DKIM の署名は、DKIM-Signature ヘッダにある d タグにあるドメインに対して行われる
  4. SPF は、メールヘッダの From に記載されたアドレスのドメインを検証する

正解

1, 2, 4

解説

メールの認証技術に関する問題です。

正しい記述の選択肢

    1. 「DKIM の署名は、DKIM-Signature ヘッダにある d タグにあるドメインに対して行われる」
    • 記載の通りです。

間違っている記述の選択肢

  • 1.「SPF と DKIM の両方が成功すれば、DMARC 認証は必ず成功する」
    • DMARC が成功 = pass するには、SPF と DKIM 以外にも、それぞれの「アライメント」が関係します。
    • DMARCが成功するには、「SPF が成功 and SPFアライメント(ヘッダ From とエンベロープ From が一致)が成功」 or 「DKIM が成功 and DKIM アライメント(dタグで指定されたドメインとヘッダ From が一致)」が条件となります。なので、SPF とDKIM が両方成功していても、それぞれのアライメントが両方とも失敗している場合はDMARC 認証は失敗します。
  • 2.「DMRAC 認証が失敗し、p=reject の場合は、メールは常に届かない」
    • DMARC のポリシーはあくまでも推奨であり、強制ではありません。
    • DMARC 認証が失敗し、ポリシーで reject を指定されていたとしても、メール受信者の local_policy などで DMARC ポリシーが上書きされている場合は配信することがあります。
  • 4.「SPF は、メールヘッダの From に記載されたアドレスのドメインを検証する」
    • 間違いです。SPF では、メールヘッダではなくエンベロープ From に記載されたアドレスのドメインを検証します