LoginSignup
2
1

More than 1 year has passed since last update.

同じpod内にwebコンテナ(nginxとapache2)を起動させてNodePortで外部公開してみるよ~

Last updated at Posted at 2023-05-02

こんにちは
株式会社クラスアクト インフラストラクチャ事業部の大塚です。

この記事ではタイトルの通り、podの中にnginxとapache2の2つのコンテナを起動させ、そのpodをNodePortを使って外部公開。ローカルPCのcmdからnode(k8sを動かしているサーバの事)に対してcurlを打って、pod内のコンテナにアクセスする的な遊びをやってみたいと思います。
但し、nginxとapache2はともにWebサーバとして稼働しますが、双方とも80,443ポートを使用するので、そのままだとカニバリます。そのため、apache2側のlisten portを90に変更しそれをdocker image化。そのイメージをpod内のコンテナに使用します。

イメージは以下となります。
まずubuntu22.04環境を2つ用意します。片方はdocker。もう片方はk8s(microk8s)です。
docker環境にapache2のdocker imageをpullしコンテナをデプロイ。configファイルを編集しlisten portを90に変更します。
変更しましたら、そのコンテナをdocker commitでイメージ化。docker hubにpushします。
pushしたapache2イメージと最初から用意されているnginxイメージをkubernetesの同一podにデプロイ。そのpodに対してNodePortを設定し80ポートを指定するとnginxコンテナへ接続。90ポートを指定するとapache2コンテナへ接続するようにしたいと思います。

docker imageをhubにpushして、k8s環境でデプロイしている図
kubernetes-ページ7.drawio.png

ローカルPCのcmdを起動し、k8sホストに対して80ポートを指定するとpod内のnginxコンテナに接続し、90ポートを指定するとapache2コンテナに接続する図
kubernetes-ページ8.drawio.png

apache2のdocker image準備

apache2は今回の検証で90ポートでlistenしてもらう必要があるので、そのように調整を行います。docker環境のホストはIP:192.168.2.177で動いています。
apache2イメージをdocker hubからpullします。

root@docker:~# docker pull httpd:latest 
latest: Pulling from library/httpd 
26c5c85e47da: Already exists 
2d29d3837df5: Pull complete 
2483414a5e59: Pull complete 
e78016c4ba87: Pull complete 
757908175415: Pull complete 
Digest: sha256:a182ef2350699f04b8f8e736747104eb273e255e818cd55b6d7aa50a1490ed0c 
Status: Downloaded newer image for httpd:latest 
docker.io/library/httpd:latest 
root@docker:~# docker image ls 
REPOSITORY                      TAG       IMAGE ID       CREATED         SIZE 
httpd                           latest    4b7fc736cb48   2 weeks ago     145MB 

pullしたイメージからコンテナをデプロイします。

root@docker:~# docker run -itd --name my-httpd httpd:latest 
10d9f582cffacc03ba4312a609f5e67a448c3dc718ee7bfb1e5e4cf6381c9da1 
root@docker:~# docker ps 
CONTAINER ID   IMAGE                    COMMAND              CREATED         STATUS         PORTS                                                                                            NAMES 
10d9f582cffa   httpd:latest             "httpd-foreground"   4 seconds ago   Up 2 seconds   80/tcp                                                                                           my-httpd 

デプロイしたコンテナにアクセス。configファイルを変更し90ポートでlistenする様に変更します。

root@docker:~# docker exec -it my-httpd /bin/bash
root@10d9f582cffa:/usr/local/apache2# apt update
root@10d9f582cffa:/usr/local/apache2# apt upgrade
root@10d9f582cffa:/usr/local/apache2# apt-get install vim
root@10d9f582cffa:/usr/local/apache2# cd conf 
root@10d9f582cffa:/usr/local/apache2/conf# ls 
extra  httpd.conf  magic  mime.types  original 
root@10d9f582cffa:/usr/local/apache2/conf# vi httpd.conf
root@10d9f582cffa:/usr/local/apache2/conf# grep Listen httpd.conf 
# Listen: Allows you to bind Apache to specific IP addresses and/or 
# Change this to Listen on specific IP addresses as shown below to 
#Listen 12.34.56.78:80 
Listen 90

設定をapache2に認識させるためにrestartを実行します。

root@10d9f582cffa:/usr/local/apache2/conf# apachectl restart 
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.4. Set the 'ServerName' directive globally to suppress this message

本当にこのイメージが90ポートでlistenしているか確認します。
コンテナのイメージ化をまず行います。

root@docker:~# docker ps 
CONTAINER ID   IMAGE                    COMMAND              CREATED          STATUS          PORTS                                                                                            NAMES 
10d9f582cffa   httpd:latest             "httpd-foreground"   19 minutes ago   Up 19 minutes   80/tcp                                                                                           my-httpd 
root@docker:~# docker commit my-httpd my-httpd-image 
sha256:a0942229723b2203ad131b5cd521262da6b7bc83c272fcd5f55c0c671391458e
root@docker:~# docker image ls 
REPOSITORY                      TAG       IMAGE ID       CREATED          SIZE 
my-httpd-image                  latest    a0942229723b   14 seconds ago   252MB 
httpd                           latest    4b7fc736cb48   2 weeks ago      145MB 

イメージ化したコンテナを削除します

root@docker:~# docker stop my-httpd 
my-httpd 
root@docker:~# docker rm my-httpd 
my-httpd

イメージ化したものをベースに再度apache2コンテナをデプロイします。
一番最初にデプロイしたコンテナはデフォルトの80ポートでlistenしていますが、今デプロイしたコンテナは設定変更したイメージを元にデプロイしておりますので90ポートでlistenしています。
docker runコマンドのオプションで-pを忘れないようにしましょう。

root@docker:~# docker run -itd -p 90:90 --name my-httpd my-httpd-image:latest 
0b09ac7c75729eabf4caed8927e1e0f5ce13975800a8c3d355a7e8bd173c9e34 
root@docker:~# docker ps
root@docker:~# docker ps 
CONTAINER ID   IMAGE                    COMMAND              CREATED         STATUS         PORTS                                                                                            NAMES 
0b09ac7c7572   my-httpd-image:latest    "httpd-foreground"   4 seconds ago   Up 3 seconds   80/tcp, 0.0.0.0:90->90/tcp, :::90->90/tcp        

WebブラウザでdockerのホストのIPアドレス:ポート90に対してアクセスしてみます。
動いているッぽいですね。
image.png

このdocker imageをdocker hubにpushします。

root@docker:~# docker login 
Authenticating with existing credentials... 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json. 
Configure a credential helper to remove this warning. See 
https://docs.docker.com/engine/reference/commandline/login/#credentials-store 
Login Succeeded 
root@docker:~# docker tag a0942229723b shotaohtsuka/my-httpd-image 
root@docker:~# docker image ls | grep shotaohtsuka/my-httpd-image 
shotaohtsuka/my-httpd-image     latest    a0942229723b   7 minutes ago   252MB
root@docker:~# docker push shotaohtsuka/my-httpd-image 
Using default tag: latest 
The push refers to repository [docker.io/shotaohtsuka/my-httpd-image] 
4c8603531fe3: Pushed 
355053d0995e: Mounted from library/httpd 
e7bd853ca2e7: Mounted from library/httpd 
16f81c3ee33a: Mounted from library/httpd 
568467bc0db5: Mounted from library/httpd 
ed7b0ef3bf5b: Mounted from library/httpd 
latest: digest: sha256:0e837c33efd33924cc2d6d5126903cdf4f75236e95d00bdea05b5677bcb90253 size: 1578

pushした結果です。
image02.png

yamlを使ってpodをk8sにデプロイする

k8sにpodをデプロイしていきます。なお、今回はシングルノードのk8s環境となります。
用意したyamlファイルは以下です。
podの名前は"web-pod"、コンテナの名前はnginx側が"web-nginx"、apache2側が"web-httpd"となります。ポートはnginxが80で、apache2が90でlistenすることを宣言しています。

root@sv-ohtsuka-k8s-master:~/k8s_yaml# cat httpd-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
  name: web-pod
  labels:
    app: web-app
spec:
  containers:
    - name: web-httpd
      image: shotaohtsuka/my-httpd-image
      ports:
        - name: web-httpd
          containerPort: 90
          protocol: TCP
    - name: web-nginx
      image: nginx
      ports:
        - name: web-nginx
          containerPort: 80
          protocol: TCP

このyamlファイルをベースにデプロイします。

root@sv-ohtsuka-k8s-master:~/k8s_yaml# kubectl create -f httpd-nginx.yaml
pod/web-pod created
root@sv-ohtsuka-k8s-master:~/k8s_yaml# kubectl get pod
NAME      READY   STATUS    RESTARTS   AGE
web-pod   2/2     Running   0          14s

kubectl describeでpodの詳細を確認してみます。
containersの部分で2つのコンテナ、web-httpdとweb-nginxがどのdocker imageを元にデプロイされているか、ポートは何番でlistenしているかなどが確認出来ます。

root@sv-ohtsuka-k8s-master:~/k8s_yaml# kubectl describe pod  web-pod
Name:         web-pod
Namespace:    default
Priority:     0
Node:         sv-ohtsuka-k8s-master/172.19.0.223
Start Time:   Mon, 01 May 2023 12:14:10 +0000
Labels:       app=web-app
Annotations:  cni.projectcalico.org/podIP: 10.1.114.97/32
              cni.projectcalico.org/podIPs: 10.1.114.97/32
Status:       Running
IP:           10.1.114.97
IPs:
  IP:  10.1.114.97
Containers:
  web-httpd:
    Container ID:   containerd://f9aafc2fd5f838a1dda66768f97fcd12b6ea314c4eddfaa79ad49229cb723149
    Image:          shotaohtsuka/my-httpd-image
    Image ID:       docker.io/shotaohtsuka/my-httpd-image@sha256:0e837c33efd33924cc2d6d5126903cdf4f75236e95d00bdea05b5677bcb90253
    Port:           90/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Mon, 01 May 2023 12:14:18 +0000
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-wjg99 (ro)
  web-nginx:
    Container ID:   containerd://086395ea3956ff66fe9c3829b7e1060ef7049631af5640352085290490aa064b
    Image:          nginx
    Image ID:       docker.io/library/nginx@sha256:63b44e8ddb83d5dd8020327c1f40436e37a6fffd3ef2498a6204df23be6e7e94
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Mon, 01 May 2023 12:14:19 +0000
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-wjg99 (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  kube-api-access-wjg99:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  57s   default-scheduler  Successfully assigned default/web-pod to sv-ohtsuka-k8s-master
  Normal  Pulling    58s   kubelet            Pulling image "shotaohtsuka/my-httpd-image"
  Normal  Pulled     50s   kubelet            Successfully pulled image "shotaohtsuka/my-httpd-image" in 7.313665416s (7.313676676s including waiting)
  Normal  Created    50s   kubelet            Created container web-httpd
  Normal  Started    50s   kubelet            Started container web-httpd
  Normal  Pulling    50s   kubelet            Pulling image "nginx"
  Normal  Pulled     49s   kubelet            Successfully pulled image "nginx" in 1.304934787s (1.304946093s including waiting)
  Normal  Created    49s   kubelet            Created container web-nginx
  Normal  Started    49s   kubelet            Started container web-nginx

デプロイしたpodをイメージに起こすと以下になります。
kubernetes-ページ9.drawio.png

yamlを使ってNodePortをk8sにデプロイする

k8sにNodePort serviceをデプロイしていきます。NodePortについての説明は割愛します。ざっくり言うとpodを外部に公開するLayer4のLB的な奴だと思ってます。

今回用意したyamlは以下です。
NodePortの名前は"service-httpd-nginx"、selectorでどのpodをターゲットにするかを指定してします。node(k8sのホストのこと)の30080ポートに対して接続してくるセッションがあった場合はターゲットにしたpodの80ポートに流し、30090ポートに対して接続してくるセッションがあった場合はターゲットにしたpodの90ポートに流すような設定をしています。

root@sv-ohtsuka-k8s-master:~/k8s_yaml# cat service-httpd-nginx.yaml
apiVersion: v1
kind: Service
metadata:
  name: service-httpd-nginx
spec:
  type: NodePort
  selector:
    app: web-app
  ports:
    - name: nginx-port
      port: 80
      targetPort: 80
      nodePort: 30080
    - name: httpd-port
      port: 90
      targetPort: 90
      nodePort: 30090

このyamlファイルを元にNodePortをデプロイします。

root@sv-ohtsuka-k8s-master:~/k8s_yaml# kubectl create -f service-httpd-nginx.yaml
service/service-httpd-nginx created

root@sv-ohtsuka-k8s-master:~/k8s_yaml# kubectl get service
NAME                  TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                     AGE
kubernetes            ClusterIP   10.152.183.1    <none>        443/TCP                     38h
service-httpd-nginx   NodePort    10.152.183.50   <none>        80:30080/TCP,90:30090/TCP   7s

この時のイメージです。
kubernetes-ページ9.drawio (1).png

Windows PCのcmdからk8sのホストにcurlする

Windows PCのcmdを起動し、上記の環境を構築したk8sホストに対して30080ポートと30090ポートを指定してcurlをかけてみます。k8sのホストのIPは192.168.2.30になります。

結果のlogは以下となります。30080ポートを指定した場合は"Welcome to nginx!"とあるようにnginxのHTMLファイルを取得していることが分かります。
一方で30090ポートを指定すると"It works!"とapache2のHTMLファイルを取得していることが分かります。(最もこれだけだとapache2だとわかりにくいですが・・・)

C:\Users\otsuka-shota>curl 192.168.2.30:30080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
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>

C:\Users\otsuka-shota>curl 192.168.2.30:30090
<html><body><h1>It works!</h1></body></html>

詰まったところ

この記事の最初の方にちらっと書いたのですが、k8s環境にubuntu22.04とmicrok8sを使用しました。
ubuntuのfirewallを成業するものとしてufwがありますが、これはデフォルトでinactiveとなっており、つまり全てのポートを開放していることになります。
k8sのNodePortのポート制約として30000以降のポートしか指定できないということがあるのですが、cmdから30080や30090を指定してもなぜかpodに接続出来ないような事象が散見されました。

k8s環境はESXiを使用して構築していたのですが、どうもそのESXiで30000以降のポートをセキュリティの観点からはじくような設定がされていた様子(定かではありまんが・・・)。トラブルシュートできず上手く出来ず1日無駄にしました。完全に盲点でした。なんでufwがinactiveなのにportがバグってんのかわかりませんでした汗。

kubernetes-ページ10.drawio.png

また、今回はNodePortというL4LBでpodに接続したためcurlでアクセスは出来ますが、Webブラウザではアクセス出来ません。
アクセスする為には、microk8sの場合metallbを有効にしてLoadBalancerと呼ばれるL7LBをデプロイしないといけないと思います。多分。

嘘です。Webブラウジング出来ました。

image.png

image.png

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1