容åšåéšçœ²ïŒä»æåšå°èªåš
ç³»åäžïŒåºç¡è®Ÿæœç¯ · 第6ç¯
è¿è®°åŸ"åå€äž€ç¹èµ·æ¥åæ»"ç婿¢ŠåïŒæåšéšçœ²äžå°æå¡åšïŒèŠä»å®è£ äŸèµãé 眮ç¯å¢ãäžäŒ 代ç ãé坿å¡âŠâŠæ¯äžæ¥éœå¯èœåºéãæŽèŠåœçæ¯ïŒåŒåç¯å¢èœè·ïŒæµè¯ç¯å¢èœè·ïŒäžäžç产就厩ââ"æè¿èŸ¹æææ¯å¥œç"æäºææ åç蟩解ã
容åšåæ¹åäºè¿äžåãå®è®©éšçœ²ä»"æå·¥äœå"è¿åå°"æµæ°Žçº¿å·¥å"ïŒè®©"äžæ¬¡æå»ºïŒå°å€è¿è¡"æäžºç°å®ã
ä»å€©æä»¬æ¥èè容åšåéšçœ²çæŒè¿åçšïŒçç仿åšå°èªåšïŒæä»¬ç»åäºä»ä¹ã
äžãéšçœ²æ¹åŒçæŒè¿
1.1 ç©çæºæ¶ä»£
ææ©çæ¶åïŒåºçšçŽæ¥éšçœ²åšç©çæå¡åšäžã
- éèŽæå¡åšïŒçåŸ å°èާ
- å®è£ æäœç³»ç»ïŒé 眮çœç»
- å®è£ è¿è¡æ¶ç¯å¢ïŒJavaãPython çïŒ
- éšçœ²åºçšïŒé 眮å¯åšèæ¬
- é çœ®çæ§ãæ¥å¿æ¶é
- èµæºæµªè޹ïŒäžå°ç©çæºåªè·äžäžªåºçšïŒCPU å©çšçå¯èœåªæ 10%
- éšçœ²çŒæ ¢ïŒä»éèŽå°äžçº¿ïŒåšæä»¥åšè®¡
- ç¯å¢äžäžèŽïŒæ¯å°æå¡åšçé 眮å¯èœæç»åŸ®å·®åŒ
- æ©å±å°éŸïŒæµéçªå¢æ¶ïŒåŸéŸå¿«éæ©å®¹
飿¶åïŒè¿ç»Žæ¯äžäžªé«åºŠäŸèµç»éªçå²äœãè°æŽçæç³»ç»ïŒè°å°±èœæŽå¿«å°ææ¥é®é¢ãäœè¿ä¹æå³çç¥è¯éŸä»¥äŒ æ¿ïŒäžæŠèå工犻èïŒæ°äººåŸåŸæ ä»äžæã
1.2 èææºæ¶ä»£
èæåææ¯çåºç°ïŒè®©äžå°ç©çæºå¯ä»¥è¿è¡å€äžªèææºã
- èµæºå©çšçæåïŒäžå°ç©çæºè·å€äžªåºçš
- èææºéåå¯ä»¥å€å¶ïŒç¯å¢äžèŽæ§æææ¹å
- æ©å®¹æ¶å¯ä»¥å¿«éå建æ°çèææº
- å¿«ç §åèœè®©åæ»ååŸå¯è¡
- ééçº§ïŒæ¯äžªèææºéœèŠè·å®æŽçæäœç³»ç»ïŒå¯åšåé级
- èµæºåŒéïŒèæå屿¬èº«æ¶è 10-20% çèµæº
- éåèè¿ïŒèææºéååšèŸå 䞪 GBïŒäŒ èŸåååšéœæ¯èŽæ
- ä»ç¶äžå€çµæŽ»ïŒåå»ºèææºè¿æ¯å€ªæ ¢ïŒè·äžäžäžå¡åå
èææºæ¶ä»£ïŒæä»¬åŠäŒäºçšé 眮管çå·¥å ·ïŒåŠ AnsibleãPuppetïŒæ¥æ ååç¯å¢ãäœ"é 眮æŒç§»"çé®é¢äŸç¶ååšïŒæ¶éŽäžé¿ïŒåå°æºåšçé 眮ååŒå§äžäžèŽã
1.3 å®¹åšæ¶ä»£
容åšçæ žå¿ç念ïŒåºçš + ç¯å¢ = å¯ç§»æ€åå ã
容åšäžæ¯èææºïŒå®äžæš¡æå®æŽç硬件åæäœç³»ç»ïŒèæ¯å ±äº«å®¿äž»æºçå æ žïŒåªæ¯éè¿éçŠ»ææ¯è®©æ¯äžªå®¹åš"çèµ·æ¥"åç¬å ç³»ç»ã
- 蜻éïŒå®¹åšéåéåžžåªæå åå°å çŸ MB
- å¿«éïŒå®¹åšå¯åšç§çº§ïŒèéåé级
- äžèŽïŒåŒåãæµè¯ãç产ç¯å¢å®å šäžèŽ
- å¯ç§»æ€ïŒåšä»»äœæ¯æå®¹åšçç³»ç»äžè¿è¡
- çæ¬åïŒéåææç¡®ççæ¬ïŒå¯ä»¥è¿œæº¯ååæ»
容åšå让"ç¯å¢"æäžºä»£ç çäžéšåïŒé代ç äžèµ·çæ¬ç®¡çãè¿ä»æ ¹æ¬äžè§£å³äº"æè¿èŸ¹æ¯å¥œç"é®é¢ââåŠæå®¹åšåšäœ é£èŸ¹èœè·ïŒåšå«äººé£èŸ¹ä¹äžå®èœè·ã
è¿å°±æ¯äžºä»ä¹å®¹åšæäžºç°ä»£éšçœ²çäºå®æ åã
äºã容åšåçææ¯åç
èŠçæ£ç解容åšïŒæä»¬éèŠæ·±å ¥å°åºå±ïŒççå®ç©¶ç«æ¯åŠäœå·¥äœçã
2.1 å®¹åš vs èææºïŒæ¬èŽšåºå«
åŸå€äººæå®¹åšç解䞺"蜻éçº§èææº"ïŒè¿æ¯äžäžªåžžè§ç误åºãå®é äžïŒäž€è çå®ç°åçå®å šäžåïŒ
âââââââââââââââââââââââââââââââââââââââ
â åºçšçšåº A â
âââââââââââââââââââââââââââââââââââââââ€
â Guest OSïŒå®æŽæäœç³»ç»ïŒ â
âââââââââââââââââââââââââââââââââââââââ€
â Hypervisor â â 硬件èæåå±
âââââââââââââââââââââââââââââââââââââââ€
â Host OS â
âââââââââââââââââââââââââââââââââââââââ€
â ç©çæå¡åšç¡¬ä»¶ â
âââââââââââââââââââââââââââââââââââââââ
ââââââââââââ¬âââââââââââ¬âââââââââââ
â åºçš A â åºçš B â åºçš C â
ââââââââââââŒâââââââââââŒâââââââââââ€
âContainer âContainer âContainer â
â Runtime â Runtime â Runtime â â 容åšè¿è¡æ¶
ââââââââââââŽâââââââââââŽâââââââââââ€
â Host OS Kernel â â å
±äº«å
æ ž
âââââââââââââââââââââââââââââââââââ€
â ç©çæå¡åšç¡¬ä»¶ â
âââââââââââââââââââââââââââââââââââ
å ³é®åºå«ïŒ
- èææºïŒæ¯äžªèææºè¿è¡å®æŽç Guest OSïŒéè¿ Hypervisor æš¡æç¡¬ä»¶
- 容åšïŒææå®¹åšå ±äº«å®¿äž»æºå æ žïŒæ²¡æç¬ç«çæäœç³»ç»
æäžªæ¯æ¹ïŒèææºåæ¯æ¯å®¶éœçç¬ç«çæ¿åïŒæèªå·±çå°åºãå¢å£ãå±é¡¶ïŒå®¹åšååæ¯äžæ 倧楌éçå ¬å¯ïŒå ±äº«å°åºåäž»äœç»æïŒäœæ¯æ·æç¬ç«çæ¿éŽåéšéã
2.2 NamespaceïŒèµæºé犻çéæ³
Linux Namespace æ¯å®¹åšéçŠ»çæ žå¿ææ¯ïŒå®è®©å®¹åš"以䞺èªå·±ç¬å ç³»ç»"ã
| Namespace ç±»å | é犻å 容 | ææ |
|---|---|---|
| PID | è¿çš ID | 容åšå è¿çšä» PID 1 åŒå§ïŒçäžå°å®¿äž»æºè¿çš |
| Network | çœç»æ | å®¹åšæç¬ç«ççœå¡ãIPãè·¯ç±è¡šãç«¯å£ |
| Mount | æä»¶ç³»ç» | å®¹åšæç¬ç«çæä»¶ç³»ç»æèœœç¹ |
| UTS | äž»æºå | 容åšå¯ä»¥æèªå·±ç hostname |
| IPC | è¿çšéŽéä¿¡ | 容åšå è¿çšéä¿¡äžå€çé犻 |
| User | çšæ· ID | 容åšå ç root å¯ä»¥æ å°å°å®¿äž»æºçæ®éçšæ· |
åšå®¿äž»æºäžæ§è¡ïŒ
# æ¥çåœåè¿çš
ps aux
# èŸåºïŒçå°æçŸäžå䞪è¿çš
# å¯åšäžäžªå®¹åš
docker run -it alpine sh
# åšå®¹åšå
æ¥çè¿çš
ps aux
# èŸåºïŒåªçå° 1 䞪è¿çšïŒPID 1 å°±æ¯ shïŒ
è¿å°±æ¯ PID Namespace çéåââ容åšå çè¿çšçäžå°å®¿äž»æºçå ¶ä»è¿çšïŒä»¥äžºèªå·±å°±æ¯ç³»ç»ç"è倧"ã
æ¯äžªå®¹åšéœæèªå·±ççœç»æ ïŒ
# åšå®¿äž»æºäž
ip addr
# çå° eth0ãdocker0 ççœå¡
# è¿å
¥å®¹åš
docker run -it alpine sh
ip addr
# çå° eth0@ifxxïŒè¿æ¯å®¹åšç¬æçèæçœå¡
容åšéŽççœç»éä¿¡ïŒéè¿ Linux çèæçœå¡å¯¹ïŒveth pairïŒåçœæ¡¥ïŒbridgeïŒå®ç°ïŒå°±åç»æ¯æ·å ¬å¯æäºç¬ç«ççµè¯çº¿ã
2.3 CgroupsïŒèµæºéå¶ç玧ç®å
åŠæè¯Ž Namespace æ¯è®©å®¹åš"以䞺èªå·±ç¬å ç³»ç»"ïŒé£ Cgroups å°±æ¯"éå¶å®¹åšèœçšå€å°èµæº"ã
- CPUïŒéå¶ CPU 䜿çšçãç»å®å°ç¹å® CPU æ žå¿
- å åïŒéå¶å å䜿çšéïŒè¶ åºå OOM Kill
- ç£ç I/OïŒéå¶è¯»åéç
- çœç»åžŠå®œïŒéå¶çœç»æµé
- è¿çšæ°ïŒéå¶å¯å建çè¿çšæ°é
# éå¶å®¹åšæå€äœ¿çš 512MB å
åïŒ1 䞪 CPU æ žå¿
docker run -d \
--memory="512m" \
--cpus="1.0" \
--name myapp \
nginx
# éªè¯éå¶çæ
docker stats myapp
åŠæäžå éå¶ïŒäžäžªå€±æ§ç容åšå¯èœåæå®¿äž»æºææå åïŒå¯ŒèŽå ¶ä»å®¹åšè¢«è¿åžŠææ»ââè¿å«"åµé¹é»å± é®é¢"ïŒNoisy NeighborïŒãCgroups å°±æ¯é²æ¢è¿ç§æ åµç"玧ç®å"ã
Cgroups æ¬èŽšäžæ¯ Linux å æ žçäžäžªæä»¶ç³»ç»æ¥å£ïŒ
# æ¥çæäžªè¿çšç CPU éå¶
cat /sys/fs/cgroup/cpu/docker/<container_id>/cpu.cfs_quota_us
# æ¥çå
åéå¶
cat /sys/fs/cgroup/memory/docker/<container_id>/memory.limit_in_bytes
Docker åªæ¯åšåå»ºå®¹åšæ¶ïŒåè¿äºæä»¶åå ¥çžåºçæ°åŒïŒå æ žäŒèªåšæ§è¡éå¶ã
2.4 UnionFSïŒéååå±çç§å¯
Docker éå䞺ä»ä¹èœåå°"å¢éæŽæ°"ïŒçæ¡åšäº Union File SystemïŒèåæä»¶ç³»ç»ïŒã
Docker éåç±å€äžªåªè¯»å±ç»æïŒå®¹åšè¿è¡æ¶åšæäžå±æ·»å äžäžªå¯åå±ïŒ
âââââââââââââââââââââââââââââââââââ
â Container LayerïŒå¯åïŒ â â 容åšè¿è¡æ¶çä¿®æ¹åå°è¿é
âââââââââââââââââââââââââââââââââââ€
â Image Layer 3ïŒåºçšä»£ç ïŒ â â åªè¯»
âââââââââââââââââââââââââââââââââââ€
â Image Layer 2ïŒäŸèµåºïŒ â â åªè¯»
âââââââââââââââââââââââââââââââââââ€
â Image Layer 1ïŒåºç¡ OSïŒ â â åªè¯»
âââââââââââââââââââââââââââââââââââ
åœå®¹åšéèŠä¿®æ¹æäžªæä»¶æ¶ïŒ
- ä»åªè¯»å±å€å¶æä»¶å°å¯åå±
- åšå¯åå±è¿è¡ä¿®æ¹
- åç»è¯»åæ¶ïŒå¯åå±çæä»¶"èŠç"åªè¯»å±çåæä»¶
è¿æ ·åç奜å€ïŒ
- ååšé«æïŒå€äžªéåå ±äº«çžåçåºç¡å±ïŒèçç£ç空éŽ
- æå»ºå¿«éïŒå©çšçŒåïŒåªé建ååçå±
- äŒ èŸé«æïŒæåéåæ¶ïŒåªéäžèœœæ¬å°æ²¡æçå±
# æåäžäžªéå
docker pull nginx:latest
# æ¥çéååå±
docker history nginx:latest
# èŸåºç€ºäŸïŒ
# IMAGE CREATED SIZE
# 605c77e624dd 2 weeks ago 141MB â åºçšå±
# <missing> 2 weeks ago 1.04kB â é
眮å±
# <missing> 2 weeks ago 1.89kB â èæ¬å±
# <missing> 2 weeks ago 62.5MB â äŸèµå±
# <missing> 2 weeks ago 33.3MB â åºç¡å±
2.5 容åšè¿è¡æ¶ïŒä» Docker å° containerd
Docker äžæ¯å¯äžç容åšè¿è¡æ¶ïŒå®é äžïŒå®¹å𿿝æ å·²ç»æ åååæš¡ååïŒ
- runtime-specïŒå®¹åšè¿è¡æ¶æ åïŒå®ä¹åŠäœè¿è¡å®¹åš
- image-specïŒéåæ ŒåŒæ åïŒå®ä¹éåç»æ
- distribution-specïŒéåååæ åïŒå®ä¹åŠäœæšé/æåéå
DockerïŒåäœïŒâ Docker Engine â containerd + runcïŒæš¡ååïŒ
âââââââââââââââââââââââââââââââââââ
â Kubernetes / Docker CLI â â çšæ·æ¥å£
âââââââââââââââââââââââââââââââââââ€
â CRIïŒå®¹åšè¿è¡æ¶æ¥å£ïŒ â â æ 忥å£
âââââââââââââââââââââââââââââââââââ€
â containerd / CRI-O â â é«å±è¿è¡æ¶
âââââââââââââââââââââââââââââââââââ€
â runc / kata-containers â â äœå±è¿è¡æ¶
âââââââââââââââââââââââââââââââââââ€
â Linux KernelïŒNamespace/CgroupsïŒâ â å
æ žèœå
âââââââââââââââââââââââââââââââââââ
- containerdïŒé«å±è¿è¡æ¶ïŒç®¡çéåã容åšçåœåšæ
- runcïŒåºå±è¿è¡æ¶ïŒçæ£å建åè¿è¡å®¹åšè¿çš
æäžªæ¯æ¹ïŒcontainerd æ¯é€å ç»çïŒç®¡ç订åãè°åºŠïŒïŒrunc æ¯åšåžïŒçæ£åèïŒã
äžãDocker å®è·µïŒä»é¶åŒå§
3.0 Docker æ¶æäžå·¥äœåç
åšæ·±å ¥å®è·µä¹åïŒå çè§£ Docker çæ¶æïŒ
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Docker æ¶æ â
â â
â ââââââââââââââââ ââââââââââââââââââââââââââââ â
â â Docker CLI â â Docker Daemon â â
â â (客æ·ç«¯) ââââââââ¶â (dockerd) â â
â â docker run â REST â ââââââââââââââââââââââ â â
â â docker build â API â â containerd â â â
â ââââââââââââââââ â â ââââââââââââââââ â â â
â â â â runc â â â â
â â â ââââââââââââââââ â â â
â â ââââââââââââââââââââââ â â
â â ââââââââââââââââââââââ â â
â â â éåååš (OverlayFS)â â â
â â ââââââââââââââââââââââ â â
â ââââââââââââââââââââââââââââ â
â â â
â ⌠â
â ââââââââââââââââââââââââââââ â
â â Linux Kernel â â
â â (Namespaces + Cgroups) â â
â ââââââââââââââââââââââââââââ â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
åœäœ æ§è¡ docker run nginx æ¶ïŒåçäºä»ä¹ïŒ
- CLI è§£æåœä»€ïŒdocker 客æ·ç«¯è§£æåæ°
- API è°çšïŒéè¿ REST API è°çš dockerd
- é忣æ¥ïŒæ¬å°æ¯åŠæ nginx éåïŒæ²¡æåä» Registry æå
- éåæåïŒä» Docker Hub äžèœœéåå±ïŒå©çšåå±çŒåïŒ
- 容åšå建ïŒcontainerd è°çš runc å建容åš
- Namespace é犻ïŒå建ç¬ç«çè¿çšãçœç»ãæä»¶ç³»ç»åœå空éŽ
- Cgroups éå¶ïŒåºçšèµæºéå¶
- 容åšå¯åšïŒæ§è¡ nginx è¿çš
# æåéåæ¶å¯ä»¥çå°åå±äžèœœ
docker pull nginx:latest
# èŸåºç€ºäŸïŒ
# latest: Pulling from library/nginx
# a2abf6c4d29d: Pull complete â åºç¡å±
# a9edb18cadd1: Pull complete â äŸèµå±
# 589b7251471a: Pull complete â åºçšå±
# ...
åŠææ¬å°å·²ææäºå±ïŒæ¥èªå ¶ä»éåïŒïŒDocker äŒå€çšå®ä»¬ïŒå€§å€§èçäžèœœæ¶éŽåååšç©ºéŽã
3.1 Dockerfile æäœ³å®è·µ
çè§£åçåïŒæä»¬æ¥çç Docker çå®é 䜿çšã
3.1 Dockerfile æäœ³å®è·µ
Dockerfile æ¯æå»ºéåç"é æ¹"ïŒå奜 Dockerfile æ¯å®¹åšåçç¬¬äžæ¥ã
# 第äžé¶æ®µïŒæå»º
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# 第äºé¶æ®µïŒè¿è¡
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
USER node
CMD ["node", "dist/main.js"]
- 䜿çšå€é¶æ®µæå»ºïŒæå»ºåè¿è¡åçŠ»ïŒæç»éåäžå å«çŒè¯å·¥å ·
- éæ©åéçåºç¡éåïŒalpine åªæ 5MBïŒæ¯å®æŽ Ubuntu å°å åå
- å©çšçŒåïŒæ
package*.jsonåç¬å€å¶å¹¶å®è£ äŸèµïŒæŸåšCOPY . .åé¢ - äžäœ¿çš root è¿è¡ïŒ
USER nodeæåå®å šæ§ - æç¡®æŽé²ç«¯å£ïŒ
EXPOSE 3000äœäžºææ¡£è¯Žæ
# â é误瀺è
FROM ubuntu:latest
RUN apt-get update
COPY . /app
RUN cd /app && npm install
CMD ["npm", "start"]
é®é¢ïŒ
- 䜿çš
ubuntu:latestïŒéå 100MB+ïŒäžçæ¬äžç¡®å®ïŒ - 没æå©çšçŒåïŒæ¯æ¬¡éœéæ° npm installïŒ
- äœ¿çš root è¿è¡ïŒå®å šé£é©ïŒ
- æ²¡ææž ç apt çŒåïŒéåèè¿ïŒ
3.2 éåäŒåæå·§
# äœ¿çš alpine åºç¡éå
FROM alpine:3.18
# åšåäžå±å®è£
åæž
ç
RUN apk add --no-cache nodejs npm && \
npm install -g pnpm
# æž
ççŒå
RUN rm -rf /var/cache/apk/*
Docker äŒæé¡ºåºæ§è¡ Dockerfile çæ¯æ¡æä»€ïŒåŠææå±æ²¡æååïŒå°±äœ¿çšçŒåïŒ
# â
奜ç顺åºïŒäŸèµæŸåé¢
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
# â åç顺åºïŒä»£ç æŸåé¢
COPY . .
RUN npm ci # 代ç åäºïŒè¿äžå±å°±èŠéæ°è·
node_modules
npm-debug.log
Dockerfile
.dockerignore
.git
.gitignore
README.md
.env
coverage
.nyc_output
3.3 Docker ComposeïŒå€å®¹åšçŒæ
åæºå€å®¹åšåºæ¯ïŒDocker Compose æ¯æäœ³éæ©ã
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://db:5432/mydb
depends_on:
- db
- redis
networks:
- backend
restart: unless-stopped
db:
image: postgres:15-alpine
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=mydb
- POSTGRES_PASSWORD=secret
networks:
- backend
restart: unless-stopped
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
networks:
- backend
restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- app
networks:
- backend
restart: unless-stopped
networks:
backend:
driver: bridge
volumes:
postgres_data:
redis_data:
# å¯åšæææå¡
docker-compose up -d
# æ¥çæå¡ç¶æ
docker-compose ps
# æ¥çæ¥å¿
docker-compose logs -f app
# æ©å®¹æäžªæå¡
docker-compose up -d --scale app=3
# 忢并æž
ç
docker-compose down -v
åãKubernetesïŒå®¹åšçŒæä¹ç
åæºå®¹åšç®¡çåŸç®åïŒäœåœå®¹åšæ°éèŸŸå°æçŸäžåïŒè·šå€å°æå¡åšéšçœ²æ¶ïŒå°±éèŠäžäžª"容åšçŒæç³»ç»"ãKubernetesïŒK8sïŒå°±æ¯è¿äžªé¢åççè ã
4.1 䞺ä»ä¹éèŠ Kubernetes
- å®¹åšæäºæä¹åïŒéèŠäººå·¥ä»å ¥éå¯
- åŠäœåšå€å°æºåšäžååååžå®¹åšïŒæåšè°åºŠæçäœ
- åŠäœå®ç°å®¹åšçèªåšæ©çŒ©å®¹ïŒéèŠåèæ¬çæ§åè°æŽ
- åŠäœç®¡ç容åšä¹éŽççœç»éä¿¡ïŒé çœ®å€æ
- åŠäœæ»åšæŽæ°èäžäžææå¡ïŒæ¥éª€ç¹çïŒå®¹æåºé
Kubernetes æè¿äºé®é¢éœè§£å³äºãå®äžä» æ¯äžäžªå®¹åšè°åºŠåšïŒæŽæ¯äžäžªååžåŒç³»ç»æäœç³»ç»ã
4.2 Kubernetes æ¶æè¯Šè§£
Kubernetes ç讟计éµåŸªå äžªæ žå¿ååïŒ
- 声æåŒ APIïŒäœ åè¯ç³»ç»"ææ³èŠä»ä¹"ïŒèäžæ¯"æä¹å"
- æ§å¶åšæš¡åŒïŒæç»å¯¹æ¯ææç¶æåå®é ç¶æïŒèªåšè°å
- 埮æå¡æ¶æïŒæ¯äžªç»ä»¶ç¬ç«è¿è¡ïŒéè¿ API éä¿¡
- 坿©å±æ§ïŒéè¿ CRDïŒèªå®ä¹èµæºå®ä¹ïŒæ©å±èœå
**Master èç¹ïŒæ§å¶å¹³é¢ïŒ
ââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Master Node â
â ââââââââââââââââ ââââââââââââââââ â
â â API Server â â Scheduler â â
â â (å
¥å£+讀è¯) â â (è°åºŠå³ç) â â
â ââââââââââââââââ ââââââââââââââââ â
â ââââââââââââââââ ââââââââââââââââ â
â â Controller â â etcd â â
â â Manager â â (æ°æ®ååš) â â
â â (ç¶æç»Žæ€) â ââââââââââââââââ â
â ââââââââââââââââ â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââ
- API ServerïŒéçŸ€å ¥å£ïŒææè¯·æ±éœéè¿å®
- SchedulerïŒå³å® Pod è¿è¡åšåªäžª Node äž
- Controller ManagerïŒç»Žæ€éçŸ€ç¶æïŒåŠå¯æ¬æ°ïŒ
- etcdïŒååžåŒé®åŒååšïŒä¿åéçŸ€æææ°æ®
ââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Worker Node â
â ââââââââââââââââ ââââââââââââââââ â
â â kubelet â â kube-proxy â â
â â (èç¹ä»£ç) â â (çœç»ä»£ç) â â
â ââââââââââââââââ ââââââââââââââââ â
â ââââââââââââââââââââââââââââââââââââââââââââââ â
â â Container Runtime â â
â â (containerd / CRI-O / Docker) â â
â ââââââââââââââââââââââââââââââââââââââââââââââ â
â ââââââââââââ¬âââââââââââ¬âââââââââââ â
â â Pod 1 â Pod 2 â Pod 3 â â
â ââââââââââââŽâââââââââââŽâââââââââââ â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââ
- kubeletïŒäž Master éä¿¡ïŒç®¡çæ¬æº Pod
- kube-proxyïŒç»Žæ€çœç»è§åïŒå®ç° Service èŽèœœåè¡¡
- Container RuntimeïŒè¿è¡å®¹åšçåºå±èœ¯ä»¶
4.3 æ žå¿æŠå¿µè¯Šè§£
Pod æ¯ Kubernetes äžæå°çéšçœ²åå ïŒäžäžª Pod å¯ä»¥å å«äžäžªæå€äžªå®¹åšïŒ
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: app
image: myapp:1.0.0
ports:
- containerPort: 8080
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
- name: sidecar # 蟹蜊容åš
image: log-collector:1.0
volumeMounts:
- name: logs
mountPath: /var/log/app
volumes:
- name: logs
emptyDir: {}
- åäž Pod å ç容åšå ±äº«çœç»åœå空éŽïŒåäž IPïŒ
- å ±äº«ååšå·
- æ»æ¯è¢«äžèµ·è°åºŠå°åäžèç¹
- çåœåšæïŒPending â Running â Succeeded/Failed
Deployment 管ç Pod ç坿¬åæŽæ°çç¥ïŒ
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
spec:
replicas: 3
selector:
matchLabels:
app: myapp
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # æŽæ°æ¶æå€å€ 1 䞪 Pod
maxUnavailable: 0 # æŽæ°æ¶æå°ä¿æ 3 䞪 Pod
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:2.0.0
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
- ç»Žæ€æå®æ°éç Pod 坿¬
- æ»åšæŽæ°ååæ»
- æå忢倿޿°
- æ©å®¹å猩容
Service 䞺äžç» Pod æäŸçš³å®ç访é®å ¥å£ïŒ
apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
selector:
app: myapp
ports:
- port: 80
targetPort: 8080
type: ClusterIP # é矀å
éšè®¿é®
| ç±»å | 访é®èåŽ | 䜿çšåºæ¯ |
|---|---|---|
| ClusterIP | é矀å éš | å éšæå¡éä¿¡ |
| NodePort | é矀å€éšïŒèç¹ç«¯å£ïŒ | åŒåæµè¯ç¯å¢ |
| LoadBalancer | é矀å€éšïŒäºèŽèœœåè¡¡ïŒ | ç产ç¯å¢ |
| ExternalName | å€éšæå¡å«å | 访é®å€éšæå¡ |
# ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
database_host: "postgres.default.svc.cluster.local"
database_port: "5432"
log_level: "info"
---
# Secret
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
data:
database_password: c2VjcmV0cGFzc3dvcmQ= # base64 çŒç
4.4 å®è·µæ¡äŸïŒå®æŽçåºçšéšçœ²
# 1. æ°æ®åºéšçœ²
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: postgres
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:15-alpine
ports:
- containerPort: 5432
env:
- name: POSTGRES_DB
value: myapp
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: app-secret
key: database_password
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: postgres-data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 10Gi
---
# 2. API æå¡éšçœ²
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 3
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: myapp-api:2.0.0
ports:
- containerPort: 8080
env:
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: app-config
key: database_url
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: app-secret
key: database_password
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
---
# 3. API Service
apiVersion: v1
kind: Service
metadata:
name: api-service
spec:
selector:
app: api
ports:
- port: 80
targetPort: 8080
---
# 4. å端éšçœ²
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 2
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: nginx
image: myapp-frontend:2.0.0
ports:
- containerPort: 80
---
# 5. Ingress é
眮
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
4.5 容åšçŒæçç¥
Kubernetes æäŸäºäž°å¯çè°åºŠåçŒæèœåïŒ
spec:
nodeSelector:
disktype: ssd # è°åºŠå°æ SSD çèç¹
zone: us-west-1a # è°åºŠå°ç¹å®å¯çšåº
spec:
affinity:
# Pod äº²åæ§ïŒäžæäžª Pod é è¿
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: cache
topologyKey: kubernetes.io/hostname
# Pod åäº²åæ§ïŒäžæäžª Pod ååŒ
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: api
topologyKey: kubernetes.io/hostname
# èç¹ææ±¡ç¹ïŒåšèç¹äžæ§è¡ïŒ
kubectl taint nodes node1 dedicated=gpu:NoSchedule
# Pod å®¹å¿æ±¡ç¹
spec:
tolerations:
- key: "dedicated"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: development
spec:
hard:
requests.cpu: "10"
requests.memory: 20Gi
limits.cpu: "20"
limits.memory: 40Gi
pods: "50"
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
äºãCI/CD æµæ°Žçº¿éæ
容åšåè§£å³äº"ç¯å¢äžèŽæ§"é®é¢ïŒäœä»£ç åŠäœåæå¯éšçœ²çéåïŒåŠäœèªåšåå°éšçœ²å°ç产ç¯å¢ïŒè¿å°±éèŠ CI/CD æµæ°Žçº¿ã
5.1 CI/CD æ¯ä»ä¹
- ä»£ç æäº€åèªåšè§Šå
- èªåšæå»ºãèªåšæµè¯
- å°œæ©åç°é®é¢ïŒéäœä¿®å€ææ¬
- ç®æ ïŒè®©ä»£ç å§ç»å€äºå¯éšçœ²ç¶æ
- æç»äº€ä»ïŒä»£ç éè¿æµè¯åïŒéæ¶å¯ä»¥éšçœ²å°çäº§ïŒæåšè§ŠåïŒ
- æç»éšçœ²ïŒä»£ç éè¿æµè¯åïŒèªåšéšçœ²å°ç产ïŒå šèªåšïŒ
- ç®æ ïŒè®©éšçœ²æäžºæ¥åžžãäœé£é©çæäœ
CI/CD çæ¬èŽšæ¯å°èœ¯ä»¶äº€ä»æµçšæ ååãèªåšåïŒåå°äººäžºå¹²é¢ïŒæé«ååžæçå莚éã
5.2 宿޿µæ°Žçº¿ç€ºäŸ
# .gitlab-ci.yml
stages:
- test
- build
- deploy-staging
- deploy-production
variables:
IMAGE_NAME: registry.example.com/myapp
IMAGE_TAG: ${CI_COMMIT_SHA}
# æµè¯é¶æ®µ
test:
stage: test
image: node:18-alpine
script:
- npm ci
- npm run lint
- npm run test:unit
- npm run test:integration
coverage: '/Lines\s*:\s*(\d+.\d+)%/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
# æå»ºéå
build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker login -u $REGISTRY_USER -p $REGISTRY_PASSWORD registry.example.com
- docker build -t $IMAGE_NAME:$IMAGE_TAG .
- docker push $IMAGE_NAME:$IMAGE_TAG
# ä¹æäž latest æ çŸ
- docker tag $IMAGE_NAME:$IMAGE_TAG $IMAGE_NAME:latest
- docker push $IMAGE_NAME:latest
only:
- main
- develop
# éšçœ²å° staging
deploy-staging:
stage: deploy-staging
image: bitnami/kubectl:latest
script:
- kubectl config use-context staging-cluster
- kubectl set image deployment/myapp myapp=$IMAGE_NAME:$IMAGE_TAG -n staging
- kubectl rollout status deployment/myapp -n staging
environment:
name: staging
url: https://staging.example.com
only:
- develop
# éšçœ²å°ç产ïŒéèŠæåšè§ŠåïŒ
deploy-production:
stage: deploy-production
image: bitnami/kubectl:latest
script:
- kubectl config use-context production-cluster
# 䜿çšéäžéååžçç¥
- kubectl apply -f k8s/canary.yaml
- sleep 300 # çåŸ
5 åéè§å¯
- kubectl apply -f k8s/production.yaml
- kubectl rollout status deployment/myapp -n production
environment:
name: production
url: https://www.example.com
when: manual # æåšè§Šå
only:
- main
5.3 GitHub Actions 瀺äŸ
# .github/workflows/ci-cd.yml
name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm run test:coverage
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
files: ./coverage/lcov.info
build:
needs: test
runs-on: ubuntu-latest
outputs:
image_tag: ${{ steps.meta.outputs.tags }}
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha,prefix=
type=ref,event=branch
type=semver,pattern={{version}}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
deploy-staging:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/develop'
environment:
name: staging
url: https://staging.example.com
steps:
- uses: actions/checkout@v4
- name: Deploy to staging
run: |
echo "Deploying ${{ needs.build.outputs.image_tag }} to staging"
# è¿éå¯ä»¥æ·»å å®é
çéšçœ²åœä»€
deploy-production:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
environment:
name: production
url: https://www.example.com
steps:
- uses: actions/checkout@v4
- name: Deploy to production
run: |
echo "Deploying ${{ needs.build.outputs.image_tag }} to production"
5.4 GitOps å®è·µ
GitOps æ¯ CI/CD çè¿äžæ¥æŒè¿ïŒæ žå¿ç念æ¯ïŒGit æ¯åäžäºå®æ¥æºã
åºçšä»£ç ä»åº é
眮ä»åºïŒK8s manifestsïŒ
â â
⌠âŒ
åŒåæäº€ æŽæ°éåçæ¬
â â
⌠âŒ
CI æµæ°Žçº¿ GitOps Operator
â ïŒArgoCD/FluxïŒ
⌠â
æå»ºéåå¹¶æšé âŒ
â èªåšåæ¥å°é矀
âââââââââââââââââââââââââââââââââ
# ArgoCD Application å®ä¹
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/org/k8s-configs.git
targetRevision: HEAD
path: apps/myapp/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true # èªåšæž
çå·²å é€çèµæº
selfHeal: true # èªåšä¿®å€æŒç§»
syncOptions:
- CreateNamespace=true
GitOps çäŒå¿ïŒ
- çæ¬æ§å¶ïŒææåæŽéœæè®°åœïŒå¯è¿œæº¯ãå¯å®¡è®¡
- èªåšåæ¥ïŒéçŸ€ç¶æèªåšäž Git ä¿æäžèŽ
- æŒç§»æ£æµïŒæåšä¿®æ¹é矀äŒè¢«æ£æµå¹¶èªåšæ¢å€
- å€ç¯å¢ç®¡çïŒéè¿äžå忝/ç®åœç®¡çå€å¥ç¯å¢
å ãéšçœ²çç¥è¯Šè§£
代ç åå€å¥œåïŒåŠäœéšçœ²å°ç产ç¯å¢ïŒè¿æ¶åå°éšçœ²çç¥çéæ©ãäžåççç¥éçšäºäžåçåºæ¯ïŒæ žå¿ç®æ æ¯åšéäœé£é©çåæ¶ä¿è¯æå¡å¯çšæ§ã
6.1 æ»åšæŽæ°ïŒRolling UpdateïŒ
- éæ¥çšæ°çæ¬æ¿æ¢æ§çæ¬
- å§ç»ä¿æäžå®æ°éçå®äŸåšçº¿
- å¹³æ»è¿æž¡ïŒçšæ·æ æç¥
[ v1 v1 v1 v1 ] â [ v1 v1 v1 v2 ] â [ v1 v1 v2 v2 ] â [ v1 v2 v2 v2 ] â [ v2 v2 v2 v2 ]
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # æŽæ°è¿çšäžæå€å€ 1 䞪 Pod
maxUnavailable: 0 # æŽæ°è¿çšäžæå°ä¿æææ Pod å¯çš
- é¶åæºïŒæå¡æç»å¯çš
- èµæºå©çšçé«ïŒäžéèŠé¢å€æºåš
- åºé®é¢å¯å¿«éåæ»
- æŽæ°æéŽæ°æ§çæ¬å ±åïŒéèŠèèå Œå®¹æ§
- åæ»éèŠæ¶éŽïŒäžæ¯ç¬éŽå®æ
6.2 è绿éšçœ²ïŒBlue-GreenïŒ
- 绎æ€äž€å¥å®æŽçç¯å¢ïŒèç¯å¢å绿ç¯å¢
- æ°çæ¬éšçœ²å°ç©ºé²ç¯å¢ïŒå åéªè¯
- æµé忢尿°ç¯å¢ïŒç¬éŽå®æ
èç¯å¢(v1) âââ æµé âââ 绿ç¯å¢(空é²)
éšçœ²æ°çæ¬ v2
èç¯å¢(v1) æµé忢 绿ç¯å¢(v2)
# èè²çæ¬
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-blue
spec:
replicas: 3
selector:
matchLabels:
app: myapp
version: blue
---
# 绿è²çæ¬
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-green
spec:
replicas: 3
selector:
matchLabels:
app: myapp
version: green
---
# Service éè¿åæ¢ selector å®ç°æµé忢
apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
selector:
app: myapp
version: blue # åæ¢å° green å³å¯å®æèç»¿åæ¢
ports:
- port: 80
- 忢ç¬éŽå®æïŒçšæ·æ æç¥
- åæ»åªé忢æµéïŒç§çº§å®æ
- æ°æ§çæ¬å®å šé犻ïŒäŸ¿äºå¯¹æ¯éªè¯
- éèŠååèµæºïŒææ¬èŸé«
- æ°æ®åºè¿ç§»éèŠé¢å€å€ç
6.3 éäžéååžïŒCanaryïŒ
- å å°æ°çæ¬éšçœ²å°å°éšåçšæ·ïŒåŠ 5%ïŒ
- è§å¯å ³é®ææ ïŒé误çãå»¶è¿ãäžå¡ææ ïŒ
- 确讀æ é®é¢å鿥æ©å€§èåŽ
- åºé®é¢ç«å³åæ»ïŒåœ±åèåŽæé
[ v1 v1 v1 v1 ] â [ v1 v1 v1 v2 ] â è§å¯ â [ v1 v1 v2 v2 ] â [ v2 v2 v2 v2 ]
â 5%æµé â 50%æµé
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: myapp
spec:
hosts:
- myapp
http:
- route:
- destination:
host: myapp
subset: stable
weight: 95 # 95% æµéå°çš³å®çæ¬
- destination:
host: myapp
subset: canary
weight: 5 # 5% æµéå°éäžéçæ¬
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: myapp-rollout
spec:
replicas: 10
strategy:
canary:
steps:
- setWeight: 5 # 5% æµé
- pause: {duration: 10m} # æå 10 åéè§å¯
- setWeight: 20 # 20% æµé
- pause: {duration: 10m}
- setWeight: 50 # 50% æµé
- pause: {duration: 10m}
- setWeight: 80 # 80% æµé
- pause: {duration: 10m}
selector:
matchLabels:
app: myapp
template:
# ... Pod æš¡æ¿
- é£é©å¯æ§ïŒé®é¢åœ±åèåŽå°
- çå®ç¯å¢éªè¯ïŒæ¯æµè¯ç¯å¢æŽå¯é
- å¯ä»¥ç»å A/B æµè¯ïŒæ¶éçšæ·åéŠ
- éèŠç²Ÿç»çæµéæ§å¶èœå
- çæ§ååèŠèŠè¶³å€å®å
- æç»æ¶éŽèŸé¿
6.4 çç¥éæ©æå
| çç¥ | èµæºæ¶è | é£é©çšåºŠ | åæ»é床 | éçšåºæ¯ |
|---|---|---|---|---|
| æ»åšæŽæ° | äœ | äž | äž | æ¥åžžååž |
| è绿éšçœ² | é« | äœ | å¿« | å ³é®æå¡ãå€§çæ¬ |
| éäžé | äž | æäœ | å¿« | 倧æµéãé«é£é©åæŽ |
- åžžè§ååž â æ»åšæŽæ°
- éèŠçæ¬ â è绿 + éäžéïŒå è绿éšçœ²ïŒå鿥念éïŒ
- 玧æ¥ä¿®å€ â æ»åšæŽæ° + å¿«éåæ»
- é«é£é©åæŽ â éäžé + èªåšååæ»ïŒåºäºçæ§ææ ïŒ
éæ©çç¥æ¶ïŒéèŠåšèµæºææ¬ãé£é©æ¿åèœåãå¢éèœåä¹éŽæŸå°å¹³è¡¡ã
äžã容åšçœç»äžæå¡åç°
容åšçœç»æ¯å®¹åšåäžæå€æçé¢åä¹äžïŒè®©æä»¬æ·±å ¥çè§£å®ã
7.1 容åšçœç»æš¡å
Docker éçšççœç»æš¡åå å«äžäžªæŠå¿µïŒ
- SandboxïŒæ²ç®±ïŒïŒå å«å®¹åšççœç»æ é çœ®ïŒæ¥å£ãè·¯ç±è¡šãDNSïŒ
- EndpointïŒç«¯ç¹ïŒïŒæ²ç®±è¿æ¥å°çœç»çæ¥å£
- NetworkïŒçœç»ïŒïŒäžç»å¯çžäºéä¿¡ç端ç¹
Kubernetes éçšçæ åïŒæŽç®åïŒ
- 容åšå建æ¶è°çš CNI æä»¶é 眮çœç»
- 容åšéæ¯æ¶è°çš CNI æä»¶æž ççœç»
- æä»¶èŽèŽ£åé IPãå建çœç»è®Ÿå€ãé 眮路ç±
7.2 Docker çœç»æš¡åŒ
# æ¯äžªå®¹åšæç¬ç« IPïŒéè¿çœæ¡¥éä¿¡
docker run -d --name web1 nginx
docker run -d --name web2 nginx
# æ¥ççœç»
docker network inspect bridge
çœç»ææïŒ
âââââââââââââââââââââââââââââââââââââââ
â å®¿äž»æº â
â ââââââââââââ ââââââââââââ â
â â web1 â â web2 â â
â â172.17.0.2â â172.17.0.3â â
â ââââââ¬ââââââ ââââââ¬ââââââ â
â â â â
â âââââââââ¬ââââââââ â
â â â
â ââââââââŒâââââââ â
â â docker0 â 172.17.0.1 â
â â (çœæ¡¥) â â
â ââââââââ¬âââââââ â
â â â
â ââââââââŒâââââââ â
â â eth0 â â
â âââââââââââââââ â
âââââââââââââââââââââââââââââââââââââââ
# 容åšçŽæ¥äœ¿çšå®¿äž»æºçœç»
docker run -d --network host nginx
# æ€æ¶å®¹å𿲡æç¬ç« IPïŒçŽæ¥äœ¿çšå®¿äž»æºç«¯å£
# å®å
šéçŠ»ïŒæ²¡æçœç»
docker run -d --network none alpine
7.3 Kubernetes çœç»
- ææ Pod äžç» NAT å°±èœçžäºéä¿¡
- ææ Node éœèœäžææ Pod éä¿¡
- Pod çå°çèªå·± IP åå«äººçå°çå®ç IP æ¯äžæ ·ç
åäžäžª Pod å ç容åšå ±äº«çœç»åœå空éŽïŒ
# Pod å
ç䞀䞪容åš
spec:
containers:
- name: app
image: myapp
ports:
- containerPort: 8080
- name: sidecar
image: log-collector
# å¯ä»¥çŽæ¥è®¿é® localhost:8080
Service éè¿ kube-proxy å®ç°ïŒæäžç§æš¡åŒïŒ
- userspaceïŒkube-proxy åšçšæ·ç©ºéŽä»£çæµéïŒå·²åºåŒïŒ
- iptablesïŒéè¿ iptables è§åå DNATïŒé»è®€ïŒ
- IPVSïŒéè¿ IPVS åèŽèœœåè¡¡ïŒé«æ§èœïŒ
iptables æš¡åŒçæµéè·¯åŸïŒ
Client â ClusterIP:Port
â
iptables DNAT
â
Pod IP:Port
âââââââââââââââââââ
å€éšæµé âââââââââ¶â Ingress â
â Controller â
ââââââââââ¬âââââââââ
â
ââââââââââââââââŒâââââââââââââââ
⌠⌠âŒ
âââââââââââ âââââââââââ âââââââââââ
â Service â â Service â â Service â
â (api) â â (web) â â (admin) â
ââââââ¬âââââ ââââââ¬âââââ ââââââ¬âââââ
â â â
ââââââŒâââââ ââââââŒâââââ ââââââŒâââââ
â Pods â â Pods â â Pods â
âââââââââââ âââââââââââ âââââââââââ
7.4 Service MeshïŒæå¡çœæ ŒïŒ
åœæå¡æ°éå¢å€ïŒæå¡éŽéä¿¡ååŸå€æïŒService Mesh åºè¿èçã
ââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Istio æ§å¶å¹³é¢ â
â ââââââââââââ ââââââââââââ ââââââââââââ â
â â Pilot â â Citadel â â Galley â â
â â (æµé管ç)â â (å®å
š) â â (é
眮) â â
â ââââââââââââ ââââââââââââ ââââââââââââ â
âââââââââââââââââââââââ¬âââââââââââââââââââââââââââââââ
â äžåé
眮
âââââââââââââââŒââââââââââââââ
⌠⌠âŒ
âââââââââââ âââââââââââ âââââââââââ
â Pod A â â Pod B â â Pod C â
âââââââââââ âââââââââââ âââââââââââ
ââEnvoy ââ ââEnvoy ââ ââEnvoy ââ
ââProxy ââ ââProxy ââ ââProxy ââ
ââââââ¬âââââ ââââââ¬âââââ ââââââ¬âââââ
â â â â â â â â â
ââââââŒâââââ ââââââŒâââââ ââââââŒâââââ
ââ App ââ ââ App ââ ââ App ââ
âââââââââââ âââââââââââ âââââââââââ
âââââââââââ âââââââââââ âââââââââââ
- æµé管çïŒéäžéååžãæ éæ³šå ¥ãæµééå
- å®å šïŒmTLS å å¯ã身仜讀è¯ãææçç¥
- å¯è§æµæ§ïŒååžåŒè¿œèžªãææ æ¶éãè®¿é®æ¥å¿
# Istio æµé管ç瀺äŸ
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- match:
- headers:
end-user:
exact: jason
route:
- destination:
host: reviews
subset: v2
- route:
- destination:
host: reviews
subset: v1
å «ãååšäžæ°æ®æä¹ å
å®¹åšæ¯äžŽæ¶çïŒåŠäœæä¹ åæ°æ®ïŒ
8.1 Docker ååšæºå¶
Docker 䜿çšååšé©±åšç®¡çéåå±å容åšå±ïŒ
- Overlay2ïŒç°ä»£é»è®€é©±åšïŒæ§èœæäœ³
- Device MapperïŒæ©æé©±åšïŒæ§èœèŸå·®
- Btrfs/ZFSïŒæä»¶ç³»ç»çº§æ¯æ
# å建åœåå·
docker volume create mydata
# æèœœå°å®¹åš
docker run -v mydata:/app/data myapp
# æ¥çå·ä¿¡æ¯
docker volume inspect mydata
# æèœœå®¿äž»æºç®åœ
docker run -v /host/path:/container/path myapp
# æèœœå°å
åïŒäžŽæ¶æ°æ®ïŒ
docker run --tmpfs /tmp myapp
8.2 Kubernetes ååšäœç³»
çšæ·/åŒåè
é矀管çå
â â
⌠âŒ
âââââââââââ ââââââââââââ
â PVC â è¯·æ± â PV â æäŸ
â (声æ) â ââââââââââ¶ â (èµæº) â
âââââââââââ ââââââââââââ
â
âŒ
ââââââââââââââââ
â StorageClass â
â (ååšç±») â
ââââââââââââââââ
# StorageClass å®ä¹
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp3
---
# PVC èªåšå建 PV
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-claim
spec:
storageClassName: fast-ssd
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
æç¶æåºçšéèŠçš³å®çååšåçœç»æ è¯ïŒ
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: database
spec:
serviceName: database
replicas: 3
template:
spec:
containers:
- name: postgres
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates: # æ¯äžª Pod èªåšå建 PVC
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 10Gi
StatefulSet ä¿è¯ïŒ
- Pod æçš³å®ççœç»æ è¯ïŒ
database-0,database-1,database-2 - æ¯äžª Pod æç¬ç«ç PVCïŒæ°æ®äžäž¢å€±
- æé¡ºåºå建åå é€ïŒ0 â 1 â 2ïŒ
ä¹ã容åšå®å šæäœ³å®è·µ
容åšå垊æ¥äºäŸ¿å©ïŒäœä¹åŒå ¥äºæ°çå®å šææã
7.1 éåå®å š
# â
䜿çšå®æ¹éåïŒæå®çæ¬
FROM node:18.19.0-alpine3.19
# â äžèŠäœ¿çš latest
FROM node:latest
# äœ¿çš distroless æ alpine
FROM gcr.io/distroless/nodejs18-debian11
# æ
FROM alpine:3.19
# äœ¿çš Trivy æ«ææŒæŽ
trivy image myapp:1.0.0
# CI äžéæ
trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:1.0.0
7.2 è¿è¡æ¶å®å š
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
resources:
limits:
memory: "512Mi"
cpu: "500m"
requests:
memory: "256Mi"
cpu: "250m"
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-network-policy
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
7.3 å¯é¥ç®¡ç
# â
äœ¿çš Kubernetes Secret
env:
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: app-secret
key: password
# æäœ¿çšå€éšå¯é¥ç®¡çç³»ç»ïŒVaultãAWS Secrets ManagerïŒ
åã容åšåå®è·µæ¡äŸ
10.1 埮æå¡æ¶æè¿ç§»æ¡äŸ
âââââââââââââââââââââââââââââââââââââââ
â åäœåºçš â
â âââââââââââââââââââââââââââââââââ â
â â çšæ· â åå â 订å â æ¯ä» â åºå â â
â âââââââââââââââââââââââââââââââââ â
â âââââââââââââââââââââââââââââââââ â
â â MySQL æ°æ®åº â â
â âââââââââââââââââââââââââââââââââ â
âââââââââââââââââââââââââââââââââââââââ
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Kubernetes é矀 â
â â
â âââââââââââ âââââââââââ âââââââââââ âââââââââââ â
â â çšæ·æå¡ â â ååæå¡ â â 订åæå¡ â â æ¯ä»æå¡ â â
â â (3 pods)â â (5 pods)â â (5 pods)â â (3 pods)â â
â ââââââ¬âââââ ââââââ¬âââââ ââââââ¬âââââ ââââââ¬âââââ â
â â â â â â
â ââââââŒâââââââââââââŒâââââââââââââŒâââââââââââââŒâââââ â
â â Service Mesh (Istio) â â
â âââââââââââââââââââââââ¬ââââââââââââââââââââââââââââ â
â â â
â âââââââââââââââââââââââŒââââââââââââââââââââââââââââ â
â â Ingress Controller â â
â âââââââââââââââââââââââââââââââââââââââââââââââââââ â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
- é¶æ®µäžïŒå®¹åšå
- 建ç«ç§æéåä»åº - æ¬å°æµè¯å®¹åšååºçš
- é¶æ®µäºïŒKubernetes éšçœ²
- é 眮 ConfigMapãSecret - è®Ÿçœ®èµæºéå¶åå¥åº·æ£æ¥
- é¶æ®µäžïŒæå¡æå
- åŒå ¥æ¶æ¯éåè§£èŠ - å®ç°æå¡éŽéä¿¡ïŒgRPC/HTTPïŒ
- é¶æ®µåïŒå®ååºç¡è®Ÿæœ
- é 眮ååžåŒè¿œèžª - å®ç°èªåšå CI/CD
| ææ | è¿ç§»å | è¿ç§»å | æå |
|---|---|---|---|
| éšçœ²é¢ç | æ¯åš 1 次 | æ¯å€© 5+ 次 | 35x |
| æ 鿢倿¶éŽ | 2 å°æ¶ | 5 åé | 24x |
| èµæºå©çšç | 15% | 60% | 4x |
| æ°åèœäžçº¿åšæ | 2 䞪æ | 1 åš | 8x |
10.2 CI/CD 宿޿¡äŸ
myapp/
âââ src/ # æºä»£ç
âââ Dockerfile # æå»ºé
眮
âââ docker-compose.yml # æ¬å°åŒå
âââ k8s/ # Kubernetes é
眮
â âââ base/ # åºç¡é
眮
â âââ overlays/ # ç¯å¢å·®åŒåé
眮
â âââ staging/
â âââ production/
âââ .gitlab-ci.yml # CI/CD é
眮
âââ scripts/
âââ deploy.sh # éšçœ²èæ¬
stages:
- lint
- test
- build
- security
- deploy-staging
- integration-test
- deploy-production
variables:
IMAGE_NAME: registry.company.com/myapp
HELM_CHART: charts/myapp
# ä»£ç æ£æ¥
lint:
stage: lint
image: node:18-alpine
script:
- npm ci
- npm run lint
- npm run type-check
# åå
æµè¯
unit-test:
stage: test
image: node:18-alpine
script:
- npm ci
- npm run test:unit -- --coverage
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
coverage: '/Lines\s*:\s*(\d+.\d+)%/'
# éææµè¯
integration-test:
stage: test
image: docker:latest
services:
- docker:dind
script:
- docker-compose -f docker-compose.test.yml up -d
- docker wait test-runner
- docker logs test-runner
after_script:
- docker-compose -f docker-compose.test.yml down -v
# æå»ºéå
build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker login -u $REGISTRY_USER -p $REGISTRY_PASSWORD registry.company.com
- docker build
--build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
--build-arg VERSION=$CI_COMMIT_TAG
-t $IMAGE_NAME:$CI_COMMIT_SHA .
- docker push $IMAGE_NAME:$CI_COMMIT_SHA
only:
- main
- tags
# å®å
𿫿
security-scan:
stage: security
image: aquasec/trivy:latest
script:
- trivy image --exit-code 1 --severity HIGH,CRITICAL $IMAGE_NAME:$CI_COMMIT_SHA
allow_failure: true # äžé»ææµæ°Žçº¿ïŒäœè®°åœé®é¢
# éšçœ²å° staging
deploy-staging:
stage: deploy-staging
image: alpine/k8s:latest
script:
- kubectl config use-context staging-cluster
- helm upgrade --install myapp $HELM_CHART
--namespace staging
--set image.tag=$CI_COMMIT_SHA
--values k8s/overlays/staging/values.yaml
- kubectl rollout status deployment/myapp -n staging --timeout=300s
environment:
name: staging
url: https://staging.company.com
only:
- main
# E2E æµè¯
e2e-test:
stage: integration-test
image: cypress/included:latest
script:
- npm ci
- npm run e2e -- --config baseUrl=https://staging.company.com
artifacts:
when: always
paths:
- cypress/videos/
- cypress/screenshots/
only:
- main
# éšçœ²å°ç产
deploy-production:
stage: deploy-production
image: alpine/k8s:latest
script:
- kubectl config use-context production-cluster
# éäžéååžïŒå
éšçœ² 10% æµé
- helm upgrade --install myapp-canary $HELM_CHART
--namespace production
--set image.tag=$CI_COMMIT_SHA
--set replicaCount=1
--set canary.enabled=true
--values k8s/overlays/production/values.yaml
# çåŸ
10 åéè§å¯
- sleep 600
# æ£æ¥é误ç
- ./scripts/check-error-rate.sh || exit 1
# å
šéååž
- helm upgrade --install myapp $HELM_CHART
--namespace production
--set image.tag=$CI_COMMIT_SHA
--values k8s/overlays/production/values.yaml
# æž
çéäžé
- helm uninstall myapp-canary -n production
environment:
name: production
url: https://www.company.com
when: manual
only:
- tags
10.3 æ éææ¥æ¡äŸ
- æ¥ç Pod ç¶æ
kubectl describe pod myapp-xxx
# åç°ïŒLast State: Terminated with exit code 137
# exit code 137 = 128 + 9 = 被 SIGKILL ææ»
- æ£æ¥èµæºäœ¿çš
kubectl top pod myapp-xxx
# å
åäœ¿çšæ¥è¿ limit
- æ¥çäºä»¶
kubectl get events --field-selector involvedObject.name=myapp-xxx
# OOMKilled
resources:
requests:
memory: "256Mi"
limits:
memory: "512Mi" # å¢å éå¶
- æ¥ççœç»çç¥
kubectl get networkpolicy
- æ£æ¥ Service Mesh æ¥å¿
kubectl logs -l app=myapp -c istio-proxy
- 䜿çšååžåŒè¿œèžª
jaeger-ui æ¥çè°çšéŸ
- æ·»å è¶ æ¶åéè¯
- äŒåæ°æ®åºæ¥è¯¢
- æ·»å çæåš
# Istio è¶
æ¶åéè¯é
眮
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
spec:
http:
- route:
- destination:
host: service-b
timeout: 5s
retries:
attempts: 3
perTryTimeout: 2s
åäžãåžžè§é®é¢äžè§£å³æ¹æ¡
容åšåç¯å¢éèŠæŽåŒºå€§ççæ§èœåã
8.1 äžå€§æ¯æ±
# Fluent Bit æ¶éå®¹åšæ¥å¿
apiVersion: fluentbit.fluent.io/v1alpha2
kind: FluentBit
metadata:
name: fluent-bit
spec:
image: kubesphere/fluent-bit:v2.0.8
positionDB:
hostPath:
path: /var/log/flb-db
fluentBitConfigSelector:
matchLabels:
config: fluent-bit-config
# Prometheus ServiceMonitor
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: myapp-monitor
spec:
selector:
matchLabels:
app: myapp
endpoints:
- port: metrics
interval: 30s
# OpenTelemetry Collector
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
name: otel-collector
spec:
config: |
receivers:
otlp:
protocols:
grpc:
http:
exporters:
jaeger:
endpoint: jaeger-collector:14250
tls:
insecure: true
service:
pipelines:
traces:
receivers: [otlp]
exporters: [jaeger]
8.2 åèŠè§å
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: myapp-alerts
spec:
groups:
- name: myapp.rules
rules:
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m]))
/ sum(rate(http_requests_total[5m])) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: High error rate detected
description: Error rate is {{ $value | humanizePercentage }}
åäºãæ»ç»äžå±æ
容åšåéšçœ²çæŒè¿ïŒæ¬èŽšäžæ¯è¿ç»Žçæ åååèªåšåè¿çšãä»æåšæäœå°èªåšåæµæ°Žçº¿ïŒæä»¬ç»åäºäžäžªå ³é®è·šè¶ïŒ
- æ ååïŒå®¹åšéå让ç¯å¢å®ä¹æ ååïŒåå«"æè¿èŸ¹æ¯å¥œç"
- çŒæåïŒKubernetes 让éçŸ€ç®¡çæ ååïŒå®ç°èªæåèªåšè°åºŠ
- æµæ°Žçº¿åïŒCI/CD 让ååžæµçšæ ååïŒä»ä»£ç å°éšçœ²å šèªåš
- æçïŒéšçœ²ä»å°æ¶çº§å°åé级ïŒçè³ç§çº§
- çš³å®ïŒç¯å¢äžèŽïŒåå°å ç¯å¢å·®åŒå¯ŒèŽç诡åŒé®é¢
- çµæŽ»ïŒå¿«éæ©çŒ©å®¹ïŒä»å®¹åºå¯¹æµéåå
- å¯é ïŒå€ç§éšçœ²çç¥ïŒéäœååžé£é©ïŒæ¯æå¿«éåæ»
- å ¥éšïŒDocker åºç¡ â Docker Compose
- è¿é¶ïŒKubernetes æ žå¿æŠå¿µ â å®è·µéšçœ²
- é«çº§ïŒCI/CD æµæ°Žçº¿ â GitOps
- äžå®¶ïŒService Mesh â Platform Engineering
容åšåäžæ¯ç»ç¹ïŒèæ¯ç°ä»£åºç¡è®Ÿæœçèµ·ç¹ïŒ
- ServerlessïŒè¿äžæ¥æœè±¡åºç¡è®ŸæœïŒæéè¿è¡ïŒæäœ¿çšä»è޹
- GitOpsïŒä»¥ Git 䞺åäžäºå®æ¥æºïŒå£°æåŒç®¡çäžå
- Service MeshïŒæå¡éŽéä¿¡äžæ²å°åºç¡è®Ÿæœå±ïŒæŽç²Ÿç»çæµéæ§å¶
- Platform EngineeringïŒæå»ºå éšåŒåè å¹³å°ïŒæååŒåäœéª
- eBPFïŒå æ žçº§å¯è§æµæ§åçœç»ïŒæŽé«æãæŽå®å š
çè§£è¿äºåçïŒæèœå𿿝æŒè¿äžä¿ææž éïŒååºæ£ç¡®çæ¶æå³çãææ¯äŒåïŒäœæ žå¿ç念ââæ ååãèªåšåãå¯è§æµââå§ç»äžåã
- ç³»åäž Â· 第1ç¯ïŒæå¡æ³šåäžåç°
- ç³»åäž Â· 第2ç¯ïŒèŽèœœåè¡¡
- ç³»åäž Â· 第3ç¯ïŒé 眮äžå¿
- ç³»åäž Â· 第4ç¯ïŒæå¡çœå ³
- ç³»åäž Â· 第5ç¯ïŒæ¥å¿äžçæ§
- ç³»åäž Â· 第6ç¯ïŒå®¹åšåéšçœ²ïŒæ¬æïŒ
ð¬ è¯è®º (0)