Làm việc với Configmap và Secret trên Kubernetes
Cập nhật gần nhất: 26/10/2024
Mình lại chào các bạn 👋👋. Mong là chào hoài các bạn không chán 😂
Tiếp tục với series học Kubernetes, ở bài trước ta đã học các Deploy app lên K8S Cluster, scale, update,... Cũng gọi là tự deploy trên K8S được rồi đấy, cơ mà một trong những thứ mà hầu như ta luôn cần khi deploy đó là cấu hình, secret, biến môi trường,... những thứ mà ta cần cấu hình tuỳ biến theo từng môi trường khác nhau (dev, staging, production),...Ở bài này chúng ta sẽ cùng nhau tìm hiểu cách dùng ConfigMap và Secret để làm điều đó nhé (và còn hơn thế nữa ).
Nếu các bạn đã quen với Docker, Docker Compose, cách dùng
environment
hayenv_from
để truyền biến môi trường vào container thì bài này sẽ rất dễ xơi đấy
Lên thuyền cùng mình nào anh em ⛵️⛵️
Lấy K8S Session
Vẫn như thường lệ, trước khi bắt đầu các bạn đảm giúp mình là đã lấy được K8S Session để truy cập vào cluster của mình đẻ lát nữa ta thực hành nhé. Xem lại bài cũ giúp mình nhé
ConfigMap
Giới thiệu qua chút thì ConfigMap là 1 object lưu data dạng key-value, dùng cho các dạng data không bảo mật, không "nhạy cảm".
Ta có thể lưu string, number, boolean vào đó hoặc có thể lưu nội dung của cả 1 file text vào cũng được. 1 trong những trường hợp phổ biến nhất là ta dùng nó để lưu biến môi trường. Nghe đơn giản nhỉ ? , ta cùng nhau đi vào ví dụ cho dễ hiểu hơn nhé.
Ở bài này mình đã chuẩn bị cho các bạn ví dụ là 1 webapp rất đơn giản như sau:
- có 2 màn: login và main
- Sau khi login xong thì user được đưa vào màn main
Ví dụ về Configmap ta sẽ tập trung vào màn login nơi ta cấu hình 1 số thông tin không "nhạy cảm":
Ở trên ta có app title và Introduction là những thứ public, và có thể config được, và ta sẽ dùng ConfigMap nhé.
Đầu tiên các bạn tạo cho mình file configmap.yml
với nội dung như sau:
apiVersion: v1
kind: ConfigMap
metadata:
name: myapp-config
data:
app_name: "Hello World"
introduction.txt: |
My Introduction
Xem xem ở đây ta có gì nào:
- để tạo configmap thì
kind
ta phải để làConfigMap
- bên trong
data
là nơi ta để config của chúng ta - ta có thể để key-value đơn giản như
app_name
, value là string đơn giản làHello world
- hoặc ta cũng có thể để cả 1 file rất dài vào đây, để ý dấu
|
nhé
Rất đơn giản phải không những người anh em thiện lành
Sau đây ta apply
để tạo Configmap nhé:
kubectl apply -f configmap.yml --kubeconfig=kubernetes-config
Ta thấy in ra:
configmap/myapp-config created
Để get configmap
thì ta cũng làm như ta thường làm với Pod, service,...
kubectl get configmap --kubeconfig=kubernetes-config
--->>
myapp-config 2 4m39s
Để xem cụ thể bên trong Configmap có đúng như ở trong file manifest ta viết hay không các bạn làm như sau:
kubectl get configmap myapp-config -o yaml --kubeconfig=kubernetes-config
Ta sẽ thấy in ra kiểu kiẻu như sau:
Nom ổn áp rồi đó 😎
Tiếp sau đây ta tạo deployment nhé, các bạn tạo cho mình file myapp.yml
như sau:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
labels:
app: myapp
spec:
selector:
matchLabels:
app: myapp-pod
template:
metadata:
labels:
app: myapp-pod
spec:
securityContext:
runAsUser: 1001
runAsGroup: 1001
fsGroup: 1001
containers:
- name: myapp-container
image: maitrungduc1410/configmap-and-secret
ports:
- containerPort: 3000
name: http
resources:
requests:
memory: "128Mi"
cpu: "64m"
limits:
memory: "750Mi"
cpu: "500m"
env:
- name: APP_NAME
valueFrom:
configMapKeyRef:
name: myapp-config
key: app_name
volumeMounts:
- name: config
mountPath: "/app/storage"
readOnly: true
volumes:
- name: config
configMap:
name: myapp-config
items:
- key: "introduction.txt"
path: "introduction.txt"
---
apiVersion: v1
kind: Service
metadata:
name: myapp-svc
spec:
type: LoadBalancer
ports:
- name: http
protocol: TCP
port: 8080
targetPort: http
selector:
app: myapp-pod
Ở bên trên nom khá giống với bài trước về Deployment ấy nhỉ 🤔
Cùng điểm qua 1 số điểm chính mới nhé:
- Đầu tiên ta có
env
là danh sách các biến môi trường ta muốn truyền vào container khi start, giống vớienvironment
mà ta vẫn dùng vớidocker compose
. Ở đó ta định nghĩa 1 biến tên làAPP_NAME
, lấy giá trị từ ConfigMap (valueFrom
->configMapKeyRef
), tiếp đó ta có tên của configmapmyapp-config
và cái key trong configmap mà ta muốn lấy raapp_name
- Tiếp theo ta định nghĩa 1
volumes
tên làconfig
(tên là gì tuỳ ý các bạn nhé), lấy từ configmap tương ứng,items
là danh sách các key ta muốn lấy ra, ở đây ta chỉ muốn lấy ra 1 key trong configmap tên làintroduction.txt
và map nó vào file cùng tênintroduction.txt
- Sau khi đã định nghĩa
volumes
thì việc của ta là sử dụng nó - Bên trong phần cấu hình
containers
ta cóvolumeMounts
, đây là nơi ta sẽ tham chiếu tớivolumes
kia.name
là tên của volumes ta vừa định nghĩa,mountPath
là ta muốn mount cái volume kia vào đường dẫn nào, cuối cùng là ta córeadOnly: true
ý là ta không cho phép container ghi đè vào file
úi xồi nhiều khái niệm quá, nom volumes
rồi volumeMounts
cứ loạn hết cả lên 😪😪 lằng nhà lằng nhằng (cái này ta sẽ làm rõ hơn ở bài về volume nhé)
Bên cạnh đó mình cũng có thêm
securityContext
, để chỉ định ta muốn chạy container bằng user nào, group nào, nó sẽ override luôn cáiUSER
mà ta định nghĩa ở Dockerfile nếu có, phần này ta sẽ nói thêm ở các bài sau nhé
Nếu các bạn để ý thì sẽ thấy là volumes
và containers
được định nghĩa ngang hàng (level) với nhau:
Tức là volumes
không bị phụ thuộc vào 1 container nào mà nó có thể được dùng chung giữa nhiều container
Âu cây rồi đó, ta cùng deploy nhé:
kubectl apply -f myapp.yml --kubeconfig=kubernetes-config
Sau đó trong thời gian chờ LoadBalancer được khởi tạo (mất vài phút để bên cloud provider tạo LB) thì tranh thủ ta vọc vạch chút nhé.
Cùng chui zô container xem có gì nào 👁️👁️
À từ từ phải get
xem có pod nào mới chui zô được chứ 😂😂:
kubectl get po --kubeconfig=kubernetes-config
---->>>
NAME READY STATUS RESTARTS AGE
myapp-deployment-995b4d567-8p4fr 1/1 Running 0 18m
Gòi gòi, giờ mới chui zô container được lè 🤪
kubectl exec -it myapp-deployment-995b4d567-8p4fr --kubeconfig=kubernetes-config -- sh
đổi tên pod sao cho khớp với của các bạn nhé
Thử check user id và group id tí xem securityContext
đã được set đúng chưa nhé:
whoami
id -u
id -g
id
Ta thấy in ra như sau:
Nom có vẻ đúng rồi đấy nhỉ
App chúng ta chạy ở bài này là app NextJS. Anh em React đâu giơ tay xem cái nào 🖐️🖐️
Tiếp theo ta sẽ kiểm tra xem biến môi trường và volume của ta đã có chưa nhé:
ls -la
echo $APP_NAME
ls -la storage
cat storage/introduction.txt
Ta sẽ thấy in ra như sau:
Nom xinh tươi rồi đó nhỉ, có hết rồi 😎😎
Nếu các bạn để ý thì folder
storage
nơi ta mount volume vào nó đang nằm dưới userroot
, mặc dù group thì vẫn đúngnodejs
. Cái này ta sẽ nói ở các bài sau nhé
Ổn rồi đó, giờ chui lại ra ngoài và get service
để lấy EXTERNAL-IP nào (bấm CTRL + D để chui ra nhé):
kubectl get svc --kubeconfig=kubernetes-config
--->>>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
myapp-svc LoadBalancer 10.245.64.155 167.99.30.23 8080:32101/TCP 3m20s
Như ở trên thì Service của mình có EXTERNAL-IP là 167.99.30.23
. Giờ ta quay lại trình duyệt và kiểm tra nhé, các bạn mở trình duyệt ở địa chỉ 167.99.30.23:8080
xem nhé:
yeah, app name đã được set thành Hello World, bấm thử nút Download Introduction
ta sẽ thấy kết quả như mong đợi 🥰🥰:
tuyệt vời ông mặt trời, cảm giác như vừa giải cứu thế giới vậy 🤩🤩🤩🤩
Giờ ta thử update lại Configmap xem nhé:
apiVersion: v1
kind: ConfigMap
metadata:
name: myapp-config
data:
app_name: "My Kubernetes App"
introduction.txt: |
This is to demo how to update Configmap
Sau đó ta apply
lại Configmap nhé:
kubectl apply -f configmap.yml --kubeconfig=kubernetes-config
---->>>
configmap/myapp-config configured
Đoạn này mới vi diệu này. Ta quay trở lại trình duyệt, bấm F5, và bấm Download Introduction
, mở file download ta sẽ thấy giá trị đã được update:
Uầy, nom xịn phết nhờ, update ngay cả khi container đang chạy luôn, không cần restart lại deployment....
Chuyện, hàng xịn mà lại 😎😎
Thế nhưng các bạn để thì APP_NAME vẫn không thay đổi, ta vẫn thấy Hello world
Volume được update ngay lập tức là vì bản chất nó chằng khác gì cái volume mà ta vẫn dùng bên Docker suốt rồi, mọi thay đổi ở volume đều sẽ được mount trực tiếp vào container lúc runtime (đang chạy). Còn với biến môi trường thì ta sẽ phải restart lại deployment đấy. Ta chạy command rollout restart
nhé:
kubectl rollout restart deploy myapp-deployment --kubeconfig=kubernetes-config
Chờ một tẹo cho Pod mới được deploy xong xuôi (các bạn tự get pod
kiểm tra bao giờ thấy RUNNING là được nhé), và giờ ta quay lại trình duyệt F5:
Tuyệt vời, APP_NAME
đã được update 🥳🥳🥳. Sử dụng ConfigMap khá đơn giản ý nhỉ Ta triển tiếp phần sau nhé
Secret
Với các dạng config chung chung, không riêng tư thì ta có thể dùng Configmap như trên, nhưng còn với các dạng thông tin cần bảo mật: thông tin kết nối data, password, API key/secret, JWT secret, docker secret để pull image từ private registry,... Với những thứ riêng tư như vậy thì ta cần 1 thứ tốt hơn, K8S mang tới cho chúng ta Secret.
Secret thì có nhiều loại Secret, nhưng phổ biến và ta hay làm việc nhất là type=Opaque
, cách dùng thì nom cũng không khác gì ConfigMap, rất dễ. Ta cùng xem nhé
Tạo và sử dụng secret
Ở cái app NextJS của mình thì ta còn có thể login với email và password của admin (được config từ phía backend), login thành công vào trong thì ta sẽ có thể download được file secret. Và bởi vì những thông tin như username/password, và file secret cần bảo mật hơn nên ta sẽ đưa nó vào secret nhé.
Các bạn tạo cho mình file secret.yml
với nội dung như sau:
apiVersion: v1
kind: Secret
metadata:
name: myapp-secret
type: Opaque
stringData:
EMAIL: "admin@test.com"
PASSWORD: "123456"
secret.txt: |
My supersecret
Nhìn vào secret ta vừa định nghĩa bên trên nom khá là giống với ConfigMap luôn ý nhỉ? đơn giản ghê.
Thì như mình đã nói ở trên đây là loại secret phổ biến nhất type=Opaque
cách dùng rất đơn giản. Ta có thể truyền vào trực tiếp stringData
là dạng data thuần, raw data. Hoặc ta cũng có thể truyền vào base64. Ví dụ với file secret bên trên mà ta muốn dùng base64 thì sẽ như sau:
...
type: Opaque
data:
EMAIL: YWRtaW5AdGVzdC5jb20K
PASSWORD: MTIzNDU2Cg==
secret.txt: TXkgc3VwZXJzZWNyZXQK
chú ý rằng với data dạng base64 thì ta phải dùng
data
thay vìstringData
nhé
còn nữa là nếu ta dùng
stringData
, thì lát nữa sau khiapply
xong vàget
thì K8S sẽ show data dạng base64 thôi.
Giờ ta lưu file secret.yml
lại (bản raw, dùng stringData
ý nhé). Và apply
để tạo secret nhé:
kubectl apply -f secret.yml --kubeconfig=kubernetes-config
--->>>
secret/myapp-secret created
ta thử get danh sách các secret hiện có ở namespace nhé:
kubectl get secret --kubeconfig=kubernetes-config
--->>>
NAME TYPE DATA AGE
default-token-4lggr kubernetes.io/service-account-token 3 10m
myapp-secret Opaque 3 41s
âu cây secret của ta được tạo ngon rồi đó. Giờ ta thử get
detail xem bên trong secret của ta sau khi tạo nó nom như thế nào nhé:
kubectl get secret myapp-secret -o yaml --kubeconfig=kubernetes-config
Ta sẽ thấy dạng dạng như sau:
Như các bạn thấy thì dù file manifest của ta để là stringData
nhưng sau khi apply
thì K8S đã đổi thành data
và dùng dạng base64. Phần này K8S làm tự động ta không cần quan tâm, lát nữa dùng ta cũng không cần convert ngược lại mà cứ thế dùng thôi nhé.
Giờ ta quay lại file deployment myapp.yml
và update lại 1 chút như sau để inject
(truyền) biến môi trường vào cho phần login và cả file secret sau khi login để user có thể download nhé. Ta mở file myapp.yml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
labels:
app: myapp
spec:
selector:
matchLabels:
app: myapp-pod
template:
metadata:
labels:
app: myapp-pod
spec:
securityContext:
runAsUser: 1001
runAsGroup: 1001
fsGroup: 1001
containers:
- name: myapp-container
image: maitrungduc1410/configmap-and-secret
ports:
- containerPort: 3000
name: http
resources:
requests:
memory: "128Mi"
cpu: "64m"
limits:
memory: "750Mi"
cpu: "500m"
env:
- name: APP_NAME
valueFrom:
configMapKeyRef:
name: myapp-config
key: app_name
- name: EMAIL
valueFrom:
secretKeyRef:
name: myapp-secret
key: EMAIL
- name: PASSWORD
valueFrom:
secretKeyRef:
name: myapp-secret
key: PASSWORD
volumeMounts:
- name: config
mountPath: "/app/storage/introduction.txt"
subPath: introduction.txt
readOnly: true
- name: secret
mountPath: "/app/storage/secret.txt"
subPath: secret.txt
readOnly: true
volumes:
- name: config
configMap:
name: myapp-config
items:
- key: "introduction.txt"
path: "introduction.txt"
- name: secret
secret:
secretName: myapp-secret
items:
- key: secret.txt
path: secret.txt
---
apiVersion: v1
kind: Service
metadata:
name: myapp-svc
spec:
type: LoadBalancer
ports:
- name: http
protocol: TCP
port: 8080
targetPort: http
selector:
app: myapp-pod
Có một số thay đổi ở Deployment, (Service thì giữ nguyên). Ta cùng xem nhé:
- đầu tiên là ở
volumes
tương tự như configMap ta định nghĩa thêm 1 volume dành cho secret để mount filesecret.txt
vào, các bạn để ý những keyword, cú pháp của nó nhé, gần như tương tự config map, khác mỗi cái bên configmap để làname
thì bên secret ta để làsecretName
- Ở
env
ta định nghĩa thêm 2 biến nữa làEMAIL
vàPASSWORD
lấy từ secret, vẫn tương tự như configmap - cuối cùng là đoạn có vẻ "thay đổi nhiều nhất" là phần
volumeMounts
- ở đó giống như configmap, ta mount thêm volume của secret vào, nhưng có 1 điều là cái
mountPath
của cả 2 ta vừa update lại để dùng đường dẫn có chứa cả tên file, và ta cũng thêm cảsubPath
là tên file nữa subPath
chính là cáipath
mà ta định nghĩa ở phầnvolumes
bên dưới- còn lí do cái
mountPath
ta phải thêm cả tên file là bởi vì hiện tại ta muốn mount 2 volumes vào chung 1 đường dẫn/app/storage
mà K8S không cho phépmountPath
trùng nhau giữa cácvolumeMounts
, nếu ta để 2 cáimountPath
đều là/app/storage
như cũ thì lúcapply
sẽ có lỗi, nên ta phải thêm tên file vào cho nó khác nhau đi, và bởi vì ta dùng trực tiếp đường dẫn có cả tên file nên ta phải dùng chung vớisubPath
để lấy ra đúng file ta mong muốn từvolumes
ối dồi ôi nghe loạn cả óc, khóc ròng🤣🤣, nếu các bạn thấy khó nuốt quá thì dành ra đôi phút thiền để có thể thẩm thấu dễ hơn nhé
Oke rồi đó giờ ta apply lại deployment nào:
kubectl apply -f myapp.yml --kubeconfig=kubernetes-config
Sau đó ta chờ 1 lúc để Pod mới được deploy (các bạn từ get pod
để check status nhé), sau đó ta quay lại trình duyệt, bấm F5 và login với EMAIL
và PASSWORD
như ta định nghĩa trong file secret. Login thành công vào trong ta bấm nút Get Secret:
Mở file download lên và ta thấy được nội dung file secret của chúng ta:
Oke vậy là ta đã hoàn thành setup Secret và Configmap rồi đó .
Vọc vạch
Thử vọc thêm tí nữa nhé. Bây giờ ta thử update lại secret.yml
:
apiVersion: v1
kind: Secret
metadata:
name: myapp-secret
type: Opaque
stringData:
EMAIL: "newadmin@gmail.com"
PASSWORD: "abcdefg"
secret.txt: |
This is new secret
Sau đó ta apply
lại:
kubectl apply -f secret.yml --kubeconfig=kubernetes-config
Ngay bây giờ, đừng restart deployment vội nhé, ta chui luôn vô container để xem cái file secret.txt
đã được cập nhật chưa:
kubectl exec -it myapp-deployment-6dcc8b9b68-gpnvk --kubeconfig=kubernetes-config -- sh
đổi tên pod khi
exec
cho giống với của các bạn nhé
Sau khi vào trong ta xem file secret.txt
có gì nhé:
/app $ cat storage/secret.txt
--->>>
My supersecret
Ô, cái gì nó nổ ý nhề? 🧨🧨, ủa sao file secret lại không update nữa rồi. Khi nãy ở bên Configmap update volume cái thì bên trong nó tự động đổi luôn không cần restart mà??? 🤔🤔🤔
Lí do volume của ta không được update "realtime" vào trong container nữa là bởi vì hiện tại ta dùng subPath
để mount, và như vậy ta sẽ không nhận được update mới nữa mà phải restart lại deployment. Đây là K8S quy định chứ không phải mình tự vẽ ra nhé các bạn 🤣🤣🤣.
Bây giờ cái configmap và secret ta đều đang dùng subPath
nên khi thay đổi chúng thì ta phải restart lại deployment, các bạn thử check với Configmap xem nhé
Giờ ta restart lại deployment là được nhé:
kubectl rollout restart deploy myapp-deployment --kubeconfig=kubernetes-config
Sau đó ta quay lại trình duyệt F5, thử login với EMAIL và PASSWORD mới, vô trong ta download file secret mới được rồi đó. Các bạn tự làm phần này nhé
À tí quên, nếu các bạn để ý khi ta chui vào container và list file:
Ta để ý thấy rằng, khi ta dùng subPath
, thì ta chỉ mount file vào bên trong folder storage
sẵn có từ trước (từ build image, trong Dockerfile), do vậy permission của folder storage vẫn được bảo toàn nextjs:nodejs
, chỉ là 2 file được mount vào bên trong thì của root:nodejs
.
Nó hơi khác 1 chút so với ở đầu bài đoạn làm với Configmap, ta mount cả volume vào thẳng đường dẫn /app/storage
, tức là mount đè lên folder storage sẵn có của image, và làm cho cả folder storage
bị đặt dưới quyền root:nodejs
Về permission thì ta sẽ thảo luận dần dần ở các bài sau để làm rõ hơn nhé
Câu hỏi liên quan
Có nên push cả ConfigMap và Secret lên Git?
Câu trả lời là không, à tuỳ . nhưng best pratice là ta không bao giờ đưa thông tin "nhạy cảm" lên git, và secret cũng vậy.
Ví dụ ConfigMap của bạn chưa thông tin có thể public, không riêng tư thì có thể đưa lên được, còn Secret thì hầu như không.
Thông thường mình vẫn muốn push file secret.yml
lên Git để mọi người có thể track được file đó là gì, cấu trúc như nào. Thì trước khi git push
mình sẽ sửa lại như sau:
apiVersion: v1
kind: Secret
metadata:
name: myapp-secret
type: Opaque
stringData:
EMAIL: <PLACEHOLDER>
PASSWORD: <PLACEHOLDER>
secret.txt: <PLACEHOLDER>
Secret có những Type nào?
Ở trong bài này ta mới chỉ nói về Type=Opaque
là type phổ biến và hay dùng nhất cho Secret, nhưng Secret còn có 1 số type khác, như hình dưới:
ví dụ type dockercfg/dockerconfigjson
dùng để kết nối tới private registry để pull image, hiện tại ta pull trực tiếp từ Dockerhub Public nên không cần cái đó. Hay type service-account-token
dành cho ServiceAccount, và một số type khác.
Các type này hầu như ta khá ít phải tự tay trực tiếp tạo chúng, chúng thường được tạo luôn bằng các tool như Helm hay như lúc ta dùng package dạng cert-manager
nó cũng tự tạo cho chúng ta. Còn mấy type về docker config để pull image từ private registry thì ví dụ như mình dùng Digital Ocean thì họ có option để tự động inject (truyền) config vào luôn K8S cluster của mình nếu như mình dùng Registry của họ
Tạo Secret bằng command?
Nếu các bạn muốn đi "tàu nhanh" dùng Terminal để tạo secret thì cũng được. Ta dùng các command dạng như sau:
kubectl create secret generic prod-db-secret --from-literal=EMAIL=admin@test.com --from-literal=PASSWORD=123456
Nhưng như mình vẫn nói, thì ta luôn ưu tiên dùng file manifest tạo tất cả mọi resource trên K8S nhé, để sau này có thể puhs lên Git, dễ dàng cho việc xem lại và track thay đổi
Nom Secret có khác gì ConfigMap đâu???
Để ý thấy rằng từ lúc ta định nghĩa secret (type=Opaque) đến lúc ta dùng nó ở env
hay mount nó vào bằng volumes
thì có khác gì ConfigMap đâu??? Chả nhẽ nó được bảo mật hơn vì được hash thành base64 à, mà base64 thì làm gì có bảo mật vì nó có thể được revert 1 cách rất dễ dàng?? 🤔🤔🤔
Các bạn nói đúng suy nghĩ của mình lúc mới học K8S rồi đó, mình đã rất băn khoăn là ủa chúng có cái gì khác nhau nhỉ, mấy cái mình hay dùng bên secret thì configmap cũng có đủ cả, chả thiếu gì. Sao người ta lại phải bày vẽ ra thêm 1 loại làm gì cơ chứ?, sao không dùng 1 cái thôi????
Thì tìm được câu trả lời ở trên StackOverflow từ trực tiếp author (người tham gia vào phát triển) của 2 tính này năng này.
Đơn giản ô ý cũng chỉ nói là:
- dùng secret cho data "nhạy cảm"
- còn configmap dùng cho những thứ không nhạy cảm
- tương lai thì họ sẽ thêm nhiều feature vào cho secret hơn nữa
Nhưng thật sự với mình thì giải thích như vậy chưa làm mình "thoả mãn" vì sự khác nhau giữa chúng vẫn chưa được nói rõ lên:
- vậy sao ta không dùng luôn secret cho rồi??
- secret gọi là là"bảo mật hơn" vì nó được mã hoá base64 à? base64 thì làm gì có bảo mật vì nó có thể được revert (đảo ngược dễ dàng)??
Ở thời điểm hiện tại (2022), từ góc độ của của mình thì nó vẫn hơi giống kiểu "best pratice", đó là "ừ, cứ cái nào nhạy cảm thì nên dùng secret, thế thôi" 😅😅
Lấy toàn bộ secret vào truyền thẳng vào biến môi trường
Ở bên Docker Compose
ta có thể khai báo env_file
để truyền toàn bộ biến ở trong 1 file env nào đó vào biến môi trường, kiểu như sau:
APP_NAME="Hello World"
EMAIL=admin@test.com
PASSWORD=123456
Tương tự ở bên K8S thì ta cũng có thể truyền toàn bộ ConfigMap hay Secret vào làm biến môi trường, ở file myapp.yml
phần khai báo containers
ta thêm vào nhưu sau là được:
containers:
- name: myapp-container
image: maitrungduc1410/configmap-and-secret
envFrom:
- secretRef:
name: myapp-secret
- configMapRef:
name: myapp-config
Kiểu này mình khá là hay dùng, vì đơn giản và tiện lợi, mình thường tổ chức các file secret/configmap kiểu:
- file chỉ chứa biến môi trường ra 1 kiểu:
apiVersion: v1
kind: Secret
metadata:
name: myapp-secret
type: Opaque
stringData:
EMAIL: "newadmin@gmail.com"
PASSWORD: "abcdefg"
- còn lại nếu file có chứa nội dung dài, dạng text bất kì thì đưa ra thành các configmap/secret riêng:
apiVersion: v1
kind: Secret
metadata:
name: myapp-secret
type: Opaque
stringData:
file1.txt: |
This is new secret
file2.txt: |
This is new secret
Và như vậy thì khi mình muốn truyền toàn bộ configmap hay secret vào env
sẽ tiện hơn, đỡ bị mix giữa biến môi trường và những dạng text kiểu file. Đây là hướng đi cá nhân thôi nhé, còn hoàn toàn tuỳ các bạn
Với secret nên dùng stringData
hay data
Câu trả lời là tuỳ các bạn nhé, vì stringData
thì sau khi apply
nó cũng được K8S convert thành data
, và giữa 2 cái chẳng cái nào bảo mật hơn vì base64 của data
thì cũng dễ dàng được revert
Thôi bỏ qua ConfigMap, cứ dùng Secret cho lành
Như ở phần trên mình nói về sự khác biệt giữa ConfigMap và Secret. Thì với những dữ liệu dạng không "nhạy cảm" thì ta có thể dùng ConfigMap thay vì Secret.
Nhưng thật sự nếu các bạn nói là thôi cứ dùng Secret cho lành thì cũng không sao cả
Mà kể ra nếu các bạn biết chia đâu là configmap đâu là secret, nó cũng cho thấy cách bạn tổ chức project, config,... tốt thế nào và bạn hiểu project của bạn ra sao: cái nào nhạy cảm, cái nào không,.... , vậy nên cố gắng đừng máy móc nhé
Chấm hết
Phùu...... bài tưởng ngắn mà dãi quá đáng 😂😂
Mong là qua bài này các bạn đã biết về ConfigMap và Secret trên K8S, các tạo, sử dụng, update,...Thật ra nói thì nhiều vậy chứ thực tế thì mình thấy cách dùng nó khá đơn giản. Phổ biến nhất là dùng nó để truyền biến môi trường vào container, đơn giản như đan rổ 😎😎
Chúc các bạn thực hành vui vẻ. Hẹn gặp lại các bạn ở những bài sau ^^
All rights reserved