หลังติดตั้ง RKE2 cluster ก็ได้ kubernetes node ขึ้นมาได้ง่ายๆ ทีนี้ปัญหามาอยู่ที่จะ host service โดยให้ cert-manager ทำการสร้าง certificate ผ่าน Letsencrypt ได้โดยอัตโนมัติ
การติดตั้ง cert-manager ทำได้ผ่าน helm ได้ตาม URL ต้นทางเลย https://cert-manager.io/docs/installation/
ในตอนที่ติดตั้งจริงๆ แล้วทำผ่าน Rancher UI ก็กดจาก Apps ได้ตรงๆ เพียงแต่เราจะไม่มีตัวเลือกให้สร้าง CRD (Custom Resource Definition) จึงแอบไปทำก่อนผ่าน helm CLI (ก็ตามในหน้าติดตั้ง อย่ารีบอ่านจนข้ามขั้นตอนนี้ไป)
หลังติดตั้ง cert-manager แล้ว การจะให้ cert-manager ทำการสร้าง certificate ให้กับ ingress ใดๆ จะต้องมีการทำ matching กันก่อน โดยการลงทะเบียน (ใช้ ClusterIssuer เลย ทำทีเดียวสะดวกดี) ให้ apply yml file ดังนี้
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-production
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
preferredChain: "ISRG Root X1"
email: your@email.com
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prd
solvers:
- http01:
ingress:
class: nginx
จากเงื่อนไขส่วนของ solver ด้วย http-01 challenge ตัว ingress ที่ต้องการให้ clusterIssuer ตัวนี้ทำขั้นตอนการขอ certificate ให้ จะต้องทำการ annotation ให้ใช้ cluster-issuer “letsencrypt-production” ตามชื่อที่สร้างไว้ ดังตัวอย่างดังนี้
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-rancher
namespace: dashcloud
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-production"
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
ingressClassName: nginx
tls:
- hosts:
- yourservice.yourdomain.com
secretName: yourservice-tls
rules:
- host: yourservice.yourdomain.com
http:
paths:
- path: /(.+)
pathType: Prefix
backend:
service:
name: yourservice
port:
number: 3000
หลังสร้างไปแล้ว พบปัญหา cert-manager ไม่ยอมสร้าง certificate ให้ (Request Approve แต่ไม่ Ready) ต้องไปดู logs ของ cert-manager pod ใน ns cert-manager พบปัญหา error ในขั้นตอน self-check ราวๆ นี้ (mask host นิดหน่อย)
E0615 13:42:25.519370 1 sync.go:190] "cert-manager/challenges: propagation check failed" err="failed to perform self check GET request 'http://yourservice.yourdomain.com/.well-known/acme-challenge/ryuGypRgK7iF2HmpQYD9m7GuPz3dkXn_bq3P7G1m4vY': Get \"http://yourservice.yourdomain.com/.well-known/acme-challenge/ryuGypRgK7iF2HmpQYD9m7GuPz3dkXn_bq3P7G1m4vY\": context deadline exceeded (Client.Timeout exceeded while awaiting headers)" resource_name="yourservice-tls-ptk8q-2512130651-1182728672" resource_namespace="dashcloud" resource_kind="Challenge" resource_version="v1" dnsName="yourservice.yourdomain.com" type="HTTP-01"
ซึ่งสาเหตุของปัญหามี 2 ส่วนคือ
name resolution
การ resolve dns จะเห็น hostname ที่เราสร้าง ingress แบบปกติ ทำให้ได้ public IP มา และเครื่องในวง k8s ไม่สามารถเรียก http/https ด้วย IP นั้นได้ ส่วนใหญ่จะเป็นปัญหาทั่วไปที่ใช้กับ NAT network คือเครื่องในวงไม่สามารถเรียกเครื่องอื่นที่อยู่ในวงเดียวกัน แก้ไขแบบลวกๆ ได้โดยการเพิ่ม dns rewrite ใน configmap ของ coredns เช่น
HTTP-01 handshake
ตอนทำ self check และตอนที่ Letsencrypt server จะตรวจสอบ HTTP-01 challenge (เปิดเว็บมาที่ /.well-known/xxxxxx) นั้นจะเรียกมาที่ port http ไม่ใช่ https ซึ่ง RKE2 ทีใช้ปัจจุบัน มีการทำ port mapping เพียงแค่ https (443) port เดียว เคสนี้จึงต้องทำการเพิ่ม port http ไปที่ตัว service ด้วย ดังนี้
