9
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

お題は不問!Qiita Engineer Festa 2023で記事投稿!

k3sでアプリケーションをデプロイし、外部からアクセスしてみた

Posted at

k3s とは軽量 Kubernetes です。しばしばメモリ消費量が少ない、バイナリが小さいなど軽量であることに注目されますが、シンプルで簡単に Kubernetes の機能を使い始められ、学習にも向いたツールです。

今回は k3s で Kubernetes クラスターを構築します。そのうえで、適当な Web アプリケーションをクラスターにデプロイし、インターネットからアクセスできるようにすることを目標とします。
私は Kubernetes 初心者なので、k3s を使って Kubernetes を学習していきたいと思います。

せっかくなので、node は 2 つにします。k3s だとそのような構成も簡単にできます。
また、各 node 間の通信は VPN で暗号化します。これも k3s だと簡単です。

バージョン情報など

$ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.2 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.2 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
$ k3s --version
k3s version v1.27.3+k3s1 (fe9604ca)
go version go1.20.5
$ sudo k3s kubectl version --short
Flag --short has been deprecated, and will be removed in the future. The --short output will become the default.
Client Version: v1.27.3+k3s1
Kustomize Version: v5.0.1
Server Version: v1.27.3+k3s1

本記事の内容に影響しないはずですが、動作確認は AWS EC2 の t3.medium インスタンスで行いました。2vCPU でメモリは 4GB です。このスペックで十分動作しました。これより小さいサーバーでも大丈夫だと思います。
なお、AWS EC2 は簡単にサーバーが作成できるから利用しただけで AWS であることは本記事の内容には関係ないはずです。

前提

最低限のスペック

k3s は軽量ですが、いくつかの最低要件があります。
詳細はRequirementsに記載されていますが、下記は特に注意と思われます。

Spec Minimum Recommended
CPU 1 core 2 cores
RAM 512 MB 1 GB

ポートを開ける

Protocol Port Source Destination Description
TCP 2379-2380 Servers Servers Required only for HA with embedded etcd
TCP 6443 Agents Servers K3s supervisor and Kubernetes API Server
UDP 8472 All nodes All nodes Required only for Flannel VXLAN
TCP 10250 All nodes All nodes Kubelet metrics
UDP 51820 All nodes All nodes Required only for Flannel Wireguard with IPv4
UDP 51821 All nodes All nodes Required only for Flannel Wireguard with IPv6

クラスターを作成

WireGuard の準備

k3s のドキュメント(Network Options)によると

The default backend for Flannel is vxlan. To enable encryption, use the wireguard-native backend.

とあります。というわけで、コンテナ間通信を暗号化するために、WireGuard を使います。
上記のドキュメントからリンクのあるWireGuard Install Guideに従い、その準備をします。と言っても ubuntu だと apt でインストールするだけです。

sudo apt install wireguard

クラスターの立ち上げ

k3s のドキュメント(Quick-Start Guide)に従い、クラスターを作成します。
今回は次のようなコマンドをクラスターを立ち上げたいサーバー内で実行しました。

curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server" sh -s - --flannel-backend wireguard-native

クラスターを立ち上げる最小のコマンドは次のとおりです。

curl -sfL https://get.k3s.io | sh -

これにいくつかのオプションを追加しています。

INSTALL_K3S_EXEC は k3s のインストール時につけるフラグを指定します。今回は server を指定しています。serveragentは k3s 用語らしいです。serverKubernetes のコントロールプレーンが動いているノードでagentはコントロールプレーンがないノードのことです。(参考:Architecture
INSTALL_K3S_EXECserverを指定することで、serverとしてノードを立ち上げています。(なお、指定しなくてもデフォルトで server として立ち上がるようではあります)
--flannel-backend wireguard-native は Flannel のバックエンドに WireGuard を使うように指定しています。これで Kubernetes のネットワークが暗号化されます。

続けて、もう一つのサーバーにagentを立ち上げます。

curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="agent --server https://xxx:6443 --token yyy" sh -s -

今回もINSTALL_K3S_EXECでオプションを指定しています。
agentを含めることで、agentとしてノードを立ち上げています。
さらにagentserverに接続するために--server--tokenを指定しています。
--serverserverのアドレスを指定します。
--tokenserverに接続するためのトークンを指定します。--tokenに指定する値はserverノードの/var/lib/rancher/k3s/server/node-tokenに書かれています。

オプションの指定の仕方はいろいろあるので、下記も参照してください。

動作確認

serverノードで次のコマンドを実行してみます。

$ sudo k3s kubectl get node

すると、agentノードも含めて 2 つのノードが表示されるはずです。

ローカルから kubectl コマンドを実行する

k3s は kubeconfig ファイルを/etc/rancher/k3s/k3s.yamlに作成しているのでこれをローカルにコピーしてきます。
kubectl コマンドが利用する kubeconfig ファイルの指定方法はいくつかありますが、例えばKUBECONFIG環境変数に指定します。

なお、Unable to connect to the server: x509: certificate is valid forというエラーが出る場合は、--insecure-skip-tls-verifyオプションをつけます。証明書の確認をスキップしますが、今回は実運用するわけではなく、学習目的なので、一旦このオプションで解決しても良いと思います。

$ export KUBECONFIG=k3s.yaml
$ kubectl get node --insecure-skip-tls-verify

ノードが 2 つ表示されるはずです。
これでローカルからクラスターを操作できるようになりました。

namespace の作成

アプリケーションをデプロイするための Namespace を作成します。
まず、kubectl get namespaceで既存の Namespace を確認します。

$ kubectl get namespace
NAME              STATUS   AGE
kube-system       Active   9m13s
default           Active   9m13s
kube-public       Active   9m13s
kube-node-lease   Active   9m13s

のようにkubeではじまる kube システム用の Namespace やdefaultが見つかるはずです。
ここに Namespace を追加します。
kubectl create namespaceコマンドで作成することもできますが、ここでは YAML ファイルを作成してkubectl applyコマンドで作成します。次のような YAML ファイルを作成します。

apiVersion: v1
kind: Namespace
metadata:
  name: app
  labels:
    name: app

そして、kubectl applyコマンドで YAML ファイルを Kubernetes に適用します。

$ # (namespace.yamlに上記のYAMLファイルを保存しているとして、)
$ kubectl apply -f namespace.yaml

kubectl get namespaceを再度実行することで、appが追加されていることがわかります。

deployment の作成

次に deployment を作成します。
再度 YAML ファイルを作成します。

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: sample-app
  name: sample-app
  namespace: app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
        - image: containous/whoami:v1.5.0
          name: whoami

ここではwhoamiという動作確認用のイメージを使います。

kubectl applyコマンドで YAML ファイルを Kubernetes に適用します。

$ # (deployment.yamlに上記のYAMLファイルを保存しているとして、)
$ kubectl apply -f deployment.yaml

Kubernetes で deployment を作成すると Pod と ReplicaSet が作成されます。次のコマンドで確認できます。

$ kubectl get pod -n app
$ kubectl get rs -n app

-nは Namespace を指定しています。

service の作成

次に service を作成します。
service とは Pod に関するネットワーク関連の設定です。

service の設定は次のような YAML ファイルで行います。

apiVersion: v1
kind: Service
metadata:
  labels:
    app: sample-app
  name: sample-app
  namespace: app
spec:
  ports:
    - name: "whoami"
      port: 18080
      protocol: TCP
      targetPort: 80
  selector:
    app: sample-app
  type: ClusterIP

次のコマンドで service を作成します。

$ # (service.yamlに上記のYAMLファイルを保存しているとして、)
$ kubectl apply -f service.yaml

service が作成されたことは

$ kubectl get svc -n app

で確認できます。
なお、type: ClusterIPなので、service はクラスター内からしかアクセスできません。現時点でサーバーに curl などでアクセスしようとしてもできないはずです。

portは何でも良いはずですが、traefik が 80 番ポートを使っているので、targetPortは 80 以外の適当な値にしています。
現時点ではサーバー内外から curl などでアクセスしようとしてもできません。

ingress の作成

最後に ingress を作成します。

ingress の設定は次のような YAML ファイルで行います。
ingress とは、クラスター外からのクラスター内の service に対するアクセスを管理するものです。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: sample-ingress
  namespace: app
spec:
  rules:
  - http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: sample-app
            port:
              number: 18080

path/apiとしています。
whoami コンテナは/にアクセスすると text で結果を返します。一方で、/apiにアクセスすると JSON で結果を返します。
今回は練習のために/ではアクセスできず、/apiにアクセスする必要があるように設定してみます。
これで ingress が「Service に対する外部からのアクセス(主に HTTP)を管理」していることが確認できるのではないかと思います。

これを次のコマンドで適用します。

$ # (ingress.yamlに上記のYAMLファイルを保存しているとして、)
$ kubectl apply -f ingress.yaml

ingress が作成されたことは

$ kubectl get ingress -n app

で確認できます。

ingress の確認

ingress が作成されると、traefik が自動的に ingress を認識してルーティングを行います。
traefik は k3s に同梱された k3s とは別の OSS です。

curl でリクエストを送信して動作確認してみます。
もしSSL certificate problemなどと証明書関連のエラーが発生すれば一旦-kオプションを付けて無視します。
どの node にリクエストを送信しても whoami コンテナのレスポンスを取得できます。whoami コンテナはコンテナがあるサーバーの IP アドレスなども返してくれるので動作確認で便利です。
また、今回は ingress に/apiと指定しているので、/にアクセスしてもレスポンスを取得できないことも確認できます。

$ curl -k https://aaa.bbb.ccc.ddd/api

これで k3s でアプリをデプロイし、外部からアクセスできるように設定できました。

参考

k3s のドキュメント

k3s 日本語ドキュメント

9
8
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
9
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?