ラズパイk3sでwordpress構築
電気代が辛いので省電力化するぞい。
調べたら意外とまとまった情報出てこなかったので自分用にメモ。
k3sインストール準備
まずRaspberry Pi ImagerでUbuntu Server 20.04をインストールします。
(22.04はうまくいかなかった)
$ cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.5 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.5 LTS"
VERSION_ID="20.04"
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"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
IPを固定化します。
$ sudo vi /etc/netplan/99_config.yaml
$ cat /etc/netplan/99_config.yaml
network:
version: 2
renderer: networkd
ethernets:
eth0:
dhcp4: false
dhcp6: false
addresses: [192.168.0.100/24]
gateway4: 192.168.0.254
nameservers:
addresses: [192.168.0.254]
cgroupのmemoryを有効化します。
cmdline.txtにcgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memoryを追記し再起動します。
$ sudo vi /boot/firmware/cmdline.txt
$ cat /boot/firmware/cmdline.txt
console=serial0,115200 dwc_otg.lpm_enable=0 console=tty1 root=LABEL=writable rootfstype=ext4 rootwait fixrtc quiet splash cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory
$ sudo reboot
k3sセットアップ
$ curl -sfL https://get.k3s.io | sh -
[INFO] Finding release for channel stable
[INFO] Using v1.25.5+k3s2 as release
[INFO] Downloading hash https://github.com/k3s-io/k3s/releases/download/v1.25.5+k3s2/sha256sum-arm64.txt
[INFO] Skipping binary downloaded, installed k3s matches hash
[INFO] Skipping installation of SELinux RPM
[INFO] Skipping /usr/local/bin/kubectl symlink to k3s, already exists
[INFO] Skipping /usr/local/bin/crictl symlink to k3s, already exists
[INFO] Skipping /usr/local/bin/ctr symlink to k3s, already exists
[INFO] Creating killall script /usr/local/bin/k3s-killall.sh
[INFO] Creating uninstall script /usr/local/bin/k3s-uninstall.sh
[INFO] env: Creating environment file /etc/systemd/system/k3s.service.env
[INFO] systemd: Creating service file /etc/systemd/system/k3s.service
[INFO] systemd: Enabling k3s unit
Created symlink /etc/systemd/system/multi-user.target.wants/k3s.service → /etc/systemd/system/k3s.service.
[INFO] No change detected so skipping service start
kubectlを実行できるようにします。
$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/rancher/k3s/k3s.yaml $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config
$ echo "export KUBECONFIG=$HOME/.kube/config" >> .bashrc
$ source .bashrc
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
ubuntu Ready control-plane,master 2m39s v1.25.5+k3s2
$ kubectl get pod -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-597584b69b-ww4tj 1/1 Running 0 2m44s
kube-system local-path-provisioner-79f67d76f8-gph6s 1/1 Running 0 2m44s
kube-system metrics-server-5c8978b444-rl74s 1/1 Running 0 2m44s
kube-system helm-install-traefik-crd-9v4vz 0/1 Completed 0 2m44s
kube-system helm-install-traefik-ff6pv 0/1 Completed 1 2m44s
kube-system svclb-traefik-9a7a7fb0-22z29 2/2 Running 0 103s
kube-system traefik-bb69b68cd-xj5l8 1/1 Running 0 103s
スクリプトからhelmをインストールします。
ドキュメントはこちら
$ curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
$ chmod 700 get_helm.sh
$ ./get_helm.sh
Downloading https://get.helm.sh/helm-v3.11.0-linux-arm64.tar.gz
Verifying checksum... Done.
Preparing to install helm into /usr/local/bin
helm installed into /usr/local/bin/helm
$ helm version
version.BuildInfo{Version:"v3.11.0", GitCommit:"472c5736ab01133de504a826bd9ee12cbe4e7904", GitTreeState:"clean", GoVersion:"go1.18.10"}
helmインストール準備します。
今回MetalLBとIngressとcert-managerを使います。
$ helm repo add metallb https://metallb.github.io/metallb
"metallb" has been added to your repositories
$ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
"ingress-nginx" has been added to your repositories
$ helm repo add jetstack https://charts.jetstack.io
"jetstack" has been added to your repositories
$ helm repo list
NAME URL
metallb https://metallb.github.io/metallb
ingress-nginx https://kubernetes.github.io/ingress-nginx
jetstack https://charts.jetstack.io
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "metallb" chart repository
...Successfully got an update from the "ingress-nginx" chart repository
...Successfully got an update from the "jetstack" chart repository
Update Complete. ⎈Happy Helming!⎈
MetalLBをhelmでインストールします。
ドキュメントはこちら
$ kubectl create namespace metallb-system
namespace/metallb-system created
$ helm install metallb metallb/metallb -n metallb-system
NAME: metallb
LAST DEPLOYED: Sat Jan 21 17:44:58 2023
NAMESPACE: metallb-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
MetalLB is now running in the cluster.
Now you can configure it via its CRs. Please refer to the metallb official docs
on how to use the CRs.
$ kubectl get all -n metallb-system
NAME READY STATUS RESTARTS AGE
pod/metallb-speaker-nx5jk 1/1 Running 0 92s
pod/metallb-controller-99b88c55f-q9tqd 1/1 Running 1 (42s ago) 92s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/metallb-webhook-service ClusterIP 10.43.98.93 <none> 443/TCP 92s
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/metallb-speaker 1 1 1 1 1 kubernetes.io/os=linux 92s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/metallb-controller 1/1 1 1 92s
NAME DESIRED CURRENT READY AGE
replicaset.apps/metallb-controller-99b88c55f 1 1 1 92s
$ vi metallb-l2-conf.yaml
$ cat metallb-l2-conf.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
namespace: metallb-system
name: first-pool
spec:
addresses:
- 192.168.0.220-192.168.0.230
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: example
namespace: metallb-system
spec:
ipAddressPools:
- first-pool
$ kubectl apply -f metallb-l2-conf.yaml
ipaddresspool.metallb.io/first-pool created
l2advertisement.metallb.io/example created
Ingressをhelmでインストールします。
前回と同じく参考にさせてもらったのはこちら
$ kubectl create ns ingress-system
namespace/ingress-system created
$ helm install ingress ingress-nginx/ingress-nginx -n ingress-system
NAME: ingress
LAST DEPLOYED: Sat Jan 21 17:52:44 2023
NAMESPACE: ingress-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The ingress-nginx controller has been installed.
It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status by running 'kubectl --namespace ingress-system get services -o wide -w ingress-ingress-nginx-controller'
An example Ingress that makes use of the controller:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example
namespace: foo
spec:
ingressClassName: nginx
rules:
- host: www.example.com
http:
paths:
- pathType: Prefix
backend:
service:
name: exampleService
port:
number: 80
path: /
# This section is only required if TLS is to be enabled for the Ingress
tls:
- hosts:
- www.example.com
secretName: example-tls
If TLS is enabled for the Ingress, a Secret containing the certificate and key must also be provided:
apiVersion: v1
kind: Secret
metadata:
name: example-tls
namespace: foo
data:
tls.crt: <base64 encoded cert>
tls.key: <base64 encoded key>
type: kubernetes.io/tls
$ kubectl --namespace ingress-system get services -o wide -w ingress-ingress-nginx-controller
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
ingress-ingress-nginx-controller LoadBalancer 10.43.128.61 192.168.0.221 80:32492/TCP,443:31592/TCP 101s app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress,app.kubernetes.io/name=ingress-nginx
cert-managerをhelmでインストールします。
ドキュメントはこちら
$ helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.11.0 --set installCRDs=true
NAME: cert-manager
LAST DEPLOYED: Sat Jan 21 18:04:22 2023
NAMESPACE: cert-manager
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
cert-manager v1.11.0 has been deployed successfully!
In order to begin issuing certificates, you will need to set up a ClusterIssuer
or Issuer resource (for example, by creating a 'letsencrypt-staging' issuer).
More information on the different types of issuers and how to configure them
can be found in our documentation:
https://cert-manager.io/docs/configuration/
For information on how to configure cert-manager to automatically provision
Certificates for Ingress resources, take a look at the `ingress-shim`
documentation:
https://cert-manager.io/docs/usage/ingress/
$ kubectl get all -n cert-manager
NAME READY STATUS RESTARTS AGE
pod/cert-manager-cainjector-547c9b8f95-f9cvr 1/1 Running 0 2m11s
pod/cert-manager-59bf757d77-dt4q6 1/1 Running 0 2m11s
pod/cert-manager-webhook-6787f645b9-86z5w 1/1 Running 0 2m11s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/cert-manager-webhook ClusterIP 10.43.251.216 <none> 443/TCP 2m11s
service/cert-manager ClusterIP 10.43.99.59 <none> 9402/TCP 2m11s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/cert-manager-cainjector 1/1 1 1 2m11s
deployment.apps/cert-manager 1/1 1 1 2m11s
deployment.apps/cert-manager-webhook 1/1 1 1 2m11s
NAME DESIRED CURRENT READY AGE
replicaset.apps/cert-manager-cainjector-547c9b8f95 1 1 1 2m11s
replicaset.apps/cert-manager-59bf757d77 1 1 1 2m11s
replicaset.apps/cert-manager-webhook-6787f645b9 1 1 1 2m11s
wordpress構築
先に名前空間を作っておきます。
$ kubectl create ns blog1
namespace/blog1 created
$ kubectl create ns ingress-wordpress
namespace/ingress-wordpress created
今回作ったyamlはこちら。
サブディレクトリで複数wordpressが使えるようにworkingDirを設定しています。
$ cat blog1-mariadb.yaml
---
apiVersion: v1
kind: Service
metadata:
name: mariadb
labels:
app: mariadb
spec:
ports:
- port: 3306
selector:
app: mariadb
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mariadb
labels:
app: mariadb
spec:
selector:
matchLabels:
app: mariadb
strategy:
type: Recreate
template:
metadata:
labels:
app: mariadb
spec:
containers:
- image: mariadb:10.9.4
name: mariadb
env:
- name: MYSQL_ROOT_PASSWORD
value: password
- name: MYSQL_DATABASE
value: wordpress
- name: MYSQL_USER
value: wordpress
- name: MYSQL_PASSWORD
value: password
ports:
- containerPort: 3306
name: mariadb
volumeMounts:
- name: mariadb-data
mountPath: /var/lib/mysql
volumes:
- name: mariadb-data
hostPath:
path: /home/ubuntu/wordpress/volumes/mariadb
$ cat blog1-wordpress.yaml
---
apiVersion: v1
kind: Service
metadata:
name: wordpress
labels:
app: wordpress
spec:
ports:
- port: 80
selector:
app: wordpress
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
labels:
app: wordpress
spec:
selector:
matchLabels:
app: wordpress
strategy:
type: Recreate
template:
metadata:
labels:
app: wordpress
spec:
containers:
- image: wordpress:php8.2-apache
name: wordpress
workingDir: /var/www/html/blog1
env:
- name: WORDPRESS_DB_HOST
value: mariadb:3306
- name: WORDPRESS_DB_USER
value: wordpress
- name: WORDPRESS_DB_PASSWORD
value: password
- name: WORDPRESS_DB_NAME
value: wordpress
ports:
- containerPort: 80
name: wordpress
volumeMounts:
- name: wp-data
mountPath: /var/www/html
volumes:
- name: wp-data
hostPath:
path: /home/ubuntu/wordpress/volumes/wp-data
blog1の名前空間にデプロイします。
$ kubectl apply -f blog1-mariadb.yaml -n blog1
service/mariadb created
deployment.apps/mariadb created
$ kubectl apply -f blog1-wordpress.yaml -n blog1
service/wordpress created
deployment.apps/wordpress created
$ kubectl get pod,svc -n blog1
NAME READY STATUS RESTARTS AGE
pod/mariadb-c6f9754d4-9q74x 1/1 Running 0 3m22s
pod/wordpress-64f8f6fdff-bc9st 1/1 Running 0 63s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/mariadb ClusterIP 10.43.228.63 <none> 3306/TCP 3m22s
service/wordpress ClusterIP 10.43.151.110 <none> 80/TCP 63s
今回はcert-managerで発行した自己証明書でhttps化します。
手順はこちら
を参考にさせていただきました。
インターネット公開する場合はLet’s Encryptを使うと思いますが、
方法はググったらたくさん出てくると思うのでそちらを試してみてください。
$ cat ca.yaml
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: selfsigned-issuer
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: selfsigned-ca
namespace: ingress-wordpress
spec:
isCA: true
commonName: selfsigned-ca
duration: 438000h
secretName: selfsigned-ca-cert
privateKey:
algorithm: RSA
size: 2048
issuerRef:
name: selfsigned-issuer
kind: ClusterIssuer
group: cert-manager.io
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: ca-issuer
namespace: ingress-wordpress
spec:
ca:
secretName: selfsigned-ca-cert
今回はwordpress.tsuchinokometal.comというドメインでアクセスしようと思います。
$ cat wordpress-cert.yaml
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: wordpress-cert
namespace: ingress-wordpress
spec:
subject:
organizations:
- MyOrg
countries:
- Japan
organizationalUnits:
- MyUnit
localities:
- Sapporo
provinces:
- Hokkaido
commonName: wordpress.tsuchinokometal.com
duration: 8760h
dnsNames:
- wordpress.tsuchinokometal.com
secretName: wordpress-cert
issuerRef:
name: ca-issuer
kind: Issuer
group: cert-manager.io
privateKey:
algorithm: RSA
size: 2048
デプロイします。
$ kubectl apply -f ca.yaml
clusterissuer.cert-manager.io/selfsigned-issuer created
certificate.cert-manager.io/selfsigned-ca created
issuer.cert-manager.io/ca-issuer created
$ kubectl get clusterissuers,certificate,issuers,secrets -n ingress-wordpress
NAME READY AGE
clusterissuer.cert-manager.io/selfsigned-issuer True 42s
NAME READY SECRET AGE
certificate.cert-manager.io/selfsigned-ca True selfsigned-ca-cert 42s
NAME READY AGE
issuer.cert-manager.io/ca-issuer True 42s
NAME TYPE DATA AGE
secret/selfsigned-ca-cert kubernetes.io/tls 3 40s
$ kubectl apply -f wordpress-cert.yaml
certificate.cert-manager.io/wordpress-cert created
$ kubectl get certificate,secret -n ingress-wordpress
NAME READY SECRET AGE
certificate.cert-manager.io/selfsigned-ca True selfsigned-ca-cert 5m31s
certificate.cert-manager.io/wordpress-cert True wordpress-cert 31s
NAME TYPE DATA AGE
secret/selfsigned-ca-cert kubernetes.io/tls 3 5m29s
secret/wordpress-cert kubernetes.io/tls 3 30s
発行した証明書をIngressで使ってみます。
名前空間の違うServiceに通信するためにExternalNameを使っています。
こちら
を参考にさせてもらってます。
$ cat ingress-wordpress.yaml
---
apiVersion: v1
kind: Service
metadata:
name: blog1-svc
namespace: ingress-wordpress
spec:
type: ExternalName
externalName: wordpress.blog1.svc.cluster.local
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-wordpress
namespace: ingress-wordpress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
ingressClassName: "nginx"
tls:
- hosts:
- wordpress.tsuchinokometal.com
secretName: wordpress-cert
rules:
- host: wordpress.tsuchinokometal.com
http:
paths:
- path: /blog1
pathType: Prefix
backend:
service:
name: blog1-svc
port:
number: 80
$ kubectl apply -f ingress-wordpress.yaml
service/blog1-svc created
ingress.networking.k8s.io/ingress-wordpress created
$ kubectl get svc,ingress -A
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default service/kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 3h34m
kube-system service/kube-dns ClusterIP 10.43.0.10 <none> 53/UDP,53/TCP,9153/TCP 3h33m
kube-system service/metrics-server ClusterIP 10.43.199.212 <none> 443/TCP 3h33m
metallb-system service/metallb-webhook-service ClusterIP 10.43.98.93 <none> 443/TCP 3h13m
kube-system service/traefik LoadBalancer 10.43.12.27 192.168.0.220 80:30386/TCP,443:30993/TCP 3h32m
ingress-system service/ingress-ingress-nginx-controller-admission ClusterIP 10.43.40.206 <none> 443/TCP 3h5m
ingress-system service/ingress-ingress-nginx-controller LoadBalancer 10.43.128.61 192.168.0.221 80:32492/TCP,443:31592/TCP 3h5m
cert-manager service/cert-manager-webhook ClusterIP 10.43.251.216 <none> 443/TCP 173m
cert-manager service/cert-manager ClusterIP 10.43.99.59 <none> 9402/TCP 173m
blog1 service/mariadb ClusterIP 10.43.228.63 <none> 3306/TCP 48m
blog1 service/wordpress ClusterIP 10.43.151.110 <none> 80/TCP 45m
ingress-wordpress service/blog1-svc ExternalName <none> wordpress.blog1.svc.cluster.local <none> 98s
NAMESPACE NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-wordpress ingress.networking.k8s.io/ingress-wordpress nginx wordpress.tsuchinokometal.com 192.168.0.221 80, 443 98s
接続テスト
IPアドレスは192.168.0.221が割り振られていますね。
wordpress.tsuchinokometal.comでアクセスできるようにhostsファイルを編集してください。
アクセスすると現状では以下のように警告が出ますので、証明書を信頼する必要があります。
証明書をエクスポートします。
$ kubectl get secrets wordpress-cert -o jsonpath='{.data.ca\.crt}' -n ingress-wordpress | base64 -d > ca.crt
macの場合はscpなどでダウンロードしたらダブルクリックしてキーチェーンアクセスを起動し、
selfsigned-caとなっている証明書が増えていると思うのでそれを信頼します。
再度アクセスすると以下の画像のようになると思います。
サブディレクトリでアクセスできるようですね。
更新もできたし問題なく使えそうかな?
blog1としていた部分を書き換えれば複数wordpressが1つのドメインでデプロイできると思います。