etcd Kubernetes ํด๋Ÿฌ์Šคํ„ฐ์˜ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ๋‹น์‚ฌ์˜ ๊ฒฝํ—˜(K8s API ์—†์Œ)

์ ์  ๋” ๋งŽ์€ ๊ณ ๊ฐ์ด ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด์˜ ์„œ๋น„์Šค์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ๋„๋ก Kubernetes ํด๋Ÿฌ์Šคํ„ฐ์— ๋Œ€ํ•œ ์•ก์„ธ์Šค๋ฅผ ์ œ๊ณตํ•ด๋‹ฌ๋ผ๊ณ  ์š”์ฒญํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ผ๋ถ€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋‚˜ ์„œ๋น„์Šค์— ์ง์ ‘ ์—ฐ๊ฒฐํ•˜๊ณ  ๋กœ์ปฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

etcd Kubernetes ํด๋Ÿฌ์Šคํ„ฐ์˜ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ๋‹น์‚ฌ์˜ ๊ฒฝํ—˜(K8s API ์—†์Œ)

์˜ˆ๋ฅผ ๋“ค์–ด ๋กœ์ปฌ ์ปดํ“จํ„ฐ์—์„œ ์„œ๋น„์Šค๋กœ ์—ฐ๊ฒฐํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. memcached.staging.svc.cluster.local. ์šฐ๋ฆฌ๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์—ฐ๊ฒฐ๋˜๋Š” ํด๋Ÿฌ์Šคํ„ฐ ๋‚ด์˜ VPN์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ํฌ๋“œ, ์„œ๋น„์Šค์˜ ์„œ๋ธŒ๋„ท์„ ์•Œ๋ฆฌ๊ณ  ํด๋Ÿฌ์Šคํ„ฐ DNS๋ฅผ ํด๋ผ์ด์–ธํŠธ์— ํ‘ธ์‹œํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋น„์Šค์— ์—ฐ๊ฒฐ์„ ์‹œ๋„ํ•  ๋•Œ memcached.staging.svc.cluster.local, ์š”์ฒญ์€ ํด๋Ÿฌ์Šคํ„ฐ DNS๋กœ ์ด๋™ํ•˜๊ณ  ์ด์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ํด๋Ÿฌ์Šคํ„ฐ ์„œ๋น„์Šค ๋„คํŠธ์›Œํฌ ๋˜๋Š” Pod ์ฃผ์†Œ์—์„œ ์ด ์„œ๋น„์Šค์˜ ์ฃผ์†Œ๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค.

kubeadm์„ ์‚ฌ์šฉํ•˜์—ฌ K8s ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๊ธฐ๋ณธ ์„œ๋น„์Šค ์„œ๋ธŒ๋„ท์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. 192.168.0.0/16์ด๊ณ  ํฌ๋“œ ๋„คํŠธ์›Œํฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. 10.244.0.0/16. ์ผ๋ฐ˜์ ์œผ๋กœ ๋ชจ๋“  ๊ฒƒ์ด ์ž˜ ์ž‘๋™ํ•˜์ง€๋งŒ ๋ช‡ ๊ฐ€์ง€ ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์„œ๋ธŒ๋„ท 192.168.*.* ํด๋ผ์ด์–ธํŠธ ์‚ฌ๋ฌด์‹ค ๋„คํŠธ์›Œํฌ์—์„œ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋ฉฐ ๊ฐœ๋ฐœ์ž ํ™ˆ ๋„คํŠธ์›Œํฌ์—์„œ๋Š” ํ›จ์”ฌ ๋” ์ž์ฃผ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ํ™ˆ ๋ผ์šฐํ„ฐ๋Š” ์ด ์„œ๋ธŒ๋„ท์—์„œ ์ž‘๋™ํ•˜๊ณ  VPN์€ ์ด๋Ÿฌํ•œ ์„œ๋ธŒ๋„ท์„ ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ํด๋ผ์ด์–ธํŠธ๋กœ ํ‘ธ์‹œํ•ฉ๋‹ˆ๋‹ค.
  • ์—ฌ๋Ÿฌ ํด๋Ÿฌ์Šคํ„ฐ(ํ”„๋กœ๋•์…˜, ์Šคํ…Œ์ด์ง€ ๋ฐ/๋˜๋Š” ์—ฌ๋Ÿฌ ๊ฐœ๋ฐœ ํด๋Ÿฌ์Šคํ„ฐ)๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  ํด๋Ÿฌ์Šคํ„ฐ๋Š” ํฌ๋“œ์™€ ์„œ๋น„์Šค์— ๋Œ€ํ•ด ๋™์ผํ•œ ์„œ๋ธŒ๋„ท์„ ๊ฐ–๊ฒŒ ๋˜๋ฏ€๋กœ ์—ฌ๋Ÿฌ ํด๋Ÿฌ์Šคํ„ฐ์˜ ์„œ๋น„์Šค๋ฅผ ๋™์‹œ์— ์ž‘์—…ํ•˜๋Š” ๋ฐ ํฐ ์–ด๋ ค์›€์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋ชจ๋“  ํด๋Ÿฌ์Šคํ„ฐ๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ๋„คํŠธ์›Œํฌ๋ฅผ ๊ฐ–๋„๋ก ๋™์ผํ•œ ํ”„๋กœ์ ํŠธ ๋‚ด์˜ ์„œ๋น„์Šค ๋ฐ ํฌ๋“œ์— ๋Œ€ํ•ด ์„œ๋กœ ๋‹ค๋ฅธ ์„œ๋ธŒ๋„ท์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์„ ์˜ค๋ž˜ ์ „๋ถ€ํ„ฐ ์ฑ„ํƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์šด์˜ ์ค‘์ธ ํด๋Ÿฌ์Šคํ„ฐ๋Š” ๋งŽ์€ ์„œ๋น„์Šค, ์ƒํƒœ ์ €์žฅ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋“ฑ์„ ์‹คํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฒ˜์Œ๋ถ€ํ„ฐ ๋กค์˜ค๋ฒ„ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ ๋‹ค์Œ ์šฐ๋ฆฌ๋Š” ์Šค์Šค๋กœ์—๊ฒŒ ์งˆ๋ฌธํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ์„œ๋ธŒ๋„ท์„ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์†”๋ฃจ์…˜ ๊ฒ€์ƒ‰

๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ๋ฐฉ๋ฒ•์€ ๋‹ค์‹œ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ClusterIP ์œ ํ˜•์˜ ์„œ๋น„์Šค. ์˜ต์…˜์œผ๋กœ, ์กฐ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค ๋“ฑ :

๋‹ค์Œ ํ”„๋กœ์„ธ์Šค์—๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ๊ตฌ์„ฑ์ด ์™„๋ฃŒ๋œ ํ›„ ํฌ๋“œ๋Š” /etc/resolv.conf์—์„œ ์ด์ „ IP๋ฅผ DNS ์ด๋ฆ„ ์„œ๋ฒ„๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
์—ฌ์ „ํžˆ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์ง€ ๋ชปํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— kubeadm Reset์„ ์‚ฌ์šฉํ•˜์—ฌ ์ „์ฒด ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์žฌ์„ค์ •ํ•˜๊ณ  ๋‹ค์‹œ ์ดˆ๊ธฐํ™”ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ ๋ชจ๋“  ์‚ฌ๋žŒ์—๊ฒŒ ์ ํ•ฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค... ์šฐ๋ฆฌ ์‚ฌ๋ก€์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์†Œ๊ฐœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ํ”Œ๋ž€๋„ฌ์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • ํด๋ผ์šฐ๋“œ์™€ ํ•˜๋“œ์›จ์–ด ๋ชจ๋‘์— ํด๋Ÿฌ์Šคํ„ฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํด๋Ÿฌ์Šคํ„ฐ์˜ ๋ชจ๋“  ์„œ๋น„์Šค๋ฅผ ์žฌ๋ฐฐํฌํ•˜๋Š” ๊ฒƒ์„ ํ”ผํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.
  • ์ผ๋ฐ˜์ ์œผ๋กœ ์ตœ์†Œํ•œ์˜ ๋ฌธ์ œ๋กœ ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Kubernetes ๋ฒ„์ „์€ 1.16.6์ž…๋‹ˆ๋‹ค(๊ทธ๋Ÿฌ๋‚˜ ์ถ”๊ฐ€ ๋‹จ๊ณ„๋Š” ๋‹ค๋ฅธ ๋ฒ„์ „์—์„œ๋„ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค).
  • ์ฃผ์š” ์ž‘์—…์€ ์„œ๋น„์Šค ์„œ๋ธŒ๋„ท๊ณผ ํ•จ๊ป˜ kubeadm์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐํฌ๋œ ํด๋Ÿฌ์Šคํ„ฐ์—์„œ 192.168.0.0/16, ๋‹ค์Œ์œผ๋กœ ๋Œ€์ฒด 172.24.0.0/16.

๊ทธ๋ฆฌ๊ณ  ์šฐ๋ฆฌ๋Š” Kubernetes์—์„œ etcd์— ๋ฌด์—‡์„ ์–ด๋–ป๊ฒŒ ์ €์žฅํ•˜๋Š”์ง€, ์ด๋ฅผ ํ†ตํ•ด ๋ฌด์—‡์„ ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์˜ค๋žซ๋™์•ˆ ๊ด€์‹ฌ์„ ๊ฐ€์ ธ์™”์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.etcd์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ณ  ๊ธฐ์กด IP ์ฃผ์†Œ(์„œ๋ธŒ๋„ท)๋ฅผ ์ƒˆ IP ์ฃผ์†Œ(์„œ๋ธŒ๋„ท)๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ์€ ์–ด๋–จ๊นŒ์š”??ยป

etcd์˜ ๋ฐ์ดํ„ฐ ์ž‘์—…์„ ์œ„ํ•ด ๊ธฐ์„ฑ ๋„๊ตฌ๋ฅผ ๊ฒ€์ƒ‰ํ–ˆ์ง€๋งŒ ๋ฌธ์ œ๋ฅผ ์™„์ „ํžˆ ํ•ด๊ฒฐํ•˜๋Š” ๋„๊ตฌ๋ฅผ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. (๊ทธ๋Ÿฐ๋ฐ etcd์—์„œ ์ง์ ‘ ๋ฐ์ดํ„ฐ๋ฅผ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ์— ๋Œ€ํ•ด ์•Œ๊ณ  ๊ณ„์‹œ๋‹ค๋ฉด ๋งํฌ๋ฅผ ์•Œ๋ ค์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.) ๊ทธ๋Ÿฌ๋‚˜ ์ข‹์€ ์ถœ๋ฐœ์ ์€ etcdhelper ์˜คํ”ˆ์‹œํ”„ํŠธ์—์„œ (์ €์ž๋“ค์—๊ฒŒ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค!).

์ด ์œ ํ‹ธ๋ฆฌํ‹ฐ๋Š” ์ธ์ฆ์„œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ etcd์— ์—ฐ๊ฒฐํ•˜๊ณ  ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ทธ๊ณณ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ls, get, dump.

etcdhelper ์ถ”๊ฐ€

๋‹ค์Œ ์ƒ๊ฐ์€ ๋…ผ๋ฆฌ์ ์ž…๋‹ˆ๋‹ค. "etcd์— ๋ฐ์ดํ„ฐ๋ฅผ ์“ฐ๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์ด ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ๋ง‰๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?"

๋‘ ๊ฐ€์ง€ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ๊ฐ–์ถ˜ etcdhelper์˜ ์ˆ˜์ •๋œ ๋ฒ„์ „์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. changeServiceCIDR ะธ changePodCIDR. ๊ทธ๋…€์—๊ฒŒ ์ฝ”๋“œ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์–ด์š” ์—ฌ๊ธฐ์—.

์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์˜ ๊ธฐ๋Šฅ์€ ๋ฌด์—‡์ธ๊ฐ€์š”? ์—ฐ์‚ฐ changeServiceCIDR:

  • ๋””์‹œ๋ฆฌ์–ผ๋ผ์ด์ €๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • CIDR์„ ๋Œ€์ฒดํ•˜๊ธฐ ์œ„ํ•ด ์ •๊ทœ์‹์„ ์ปดํŒŒ์ผํ•ฉ๋‹ˆ๋‹ค.
  • ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ClusterIP ์œ ํ˜•์„ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ์„œ๋น„์Šค๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
    • etcd์˜ ๊ฐ’์„ Go ๊ฐ์ฒด๋กœ ๋””์ฝ”๋”ฉํ•ฉ๋‹ˆ๋‹ค.
    • ์ •๊ทœ์‹์„ ์‚ฌ์šฉํ•˜์—ฌ ์ฃผ์†Œ์˜ ์ฒ˜์Œ XNUMX๋ฐ”์ดํŠธ๋ฅผ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.
    • ์„œ๋น„์Šค์— ์ƒˆ ์„œ๋ธŒ๋„ท์˜ IP ์ฃผ์†Œ๋ฅผ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.
    • ์ง๋ ฌ ๋ณ€ํ™˜๊ธฐ๋ฅผ ๋งŒ๋“ค๊ณ , Go ๊ฐœ์ฒด๋ฅผ protobuf๋กœ ๋ณ€ํ™˜ํ•˜๊ณ , etcd์— ์ƒˆ ๋ฐ์ดํ„ฐ๋ฅผ ์”๋‹ˆ๋‹ค.

๊ธฐ๋Šฅ changePodCIDR ๋ณธ์งˆ์ ์œผ๋กœ ์œ ์‚ฌ changeServiceCIDR - ์„œ๋น„์Šค ์‚ฌ์–‘์„ ํŽธ์ง‘ํ•˜๋Š” ๋Œ€์‹  ๋…ธ๋“œ์— ๋Œ€ํ•ด์„œ๋งŒ ํŽธ์ง‘ํ•˜๊ณ  ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. .spec.PodCIDR ์ƒˆ ์„œ๋ธŒ๋„ท์œผ๋กœ.

์—ฐ์Šต

์„œ๋น„์Šค CIDR ๋ณ€๊ฒฝ

์ž‘์—… ๊ตฌํ˜„ ๊ณ„ํš์€ ๋งค์šฐ ๊ฐ„๋‹จํ•˜์ง€๋งŒ ํด๋Ÿฌ์Šคํ„ฐ์˜ ๋ชจ๋“  ํฌ๋“œ๋ฅผ ๋‹ค์‹œ ์ƒ์„ฑํ•  ๋•Œ ๋‹ค์šดํƒ€์ž„์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ฃผ์š” ๋‹จ๊ณ„๋ฅผ ์„ค๋ช…ํ•œ ํ›„, ์ด๋ก ์ ์œผ๋กœ ์ด๋Ÿฌํ•œ ๋‹ค์šดํƒ€์ž„์„ ์ตœ์†Œํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ƒ๊ฐ๋„ ๊ณต์œ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ค€๋น„ ๋‹จ๊ณ„:

  • ํ•„์š”ํ•œ ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ์„ค์น˜ํ•˜๊ณ  ํŒจ์น˜๋œ etcdhelper๋ฅผ ์กฐ๋ฆฝํ•ฉ๋‹ˆ๋‹ค.
  • etcd ๋ฐฑ์—… ๋ฐ /etc/kubernetes.

serviceCIDR ๋ณ€๊ฒฝ์„ ์œ„ํ•œ ๊ฐ„๋žตํ•œ ์‹คํ–‰ ๊ณ„ํš:

  • apiserver ๋ฐ ์ปจํŠธ๋กค๋Ÿฌ ๊ด€๋ฆฌ์ž ๋งค๋‹ˆํŽ˜์ŠคํŠธ ๋ณ€๊ฒฝ
  • ์ธ์ฆ์„œ ์žฌ๋ฐœ๊ธ‰;
  • etcd์—์„œ ClusterIP ์„œ๋น„์Šค๋ฅผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.
  • ํด๋Ÿฌ์Šคํ„ฐ์˜ ๋ชจ๋“  ํฌ๋“œ๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ์ „์ฒด ์ž‘์—… ์ˆœ์„œ๋ฅผ ์ž์„ธํžˆ ์„ค๋ช…ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

1. ๋ฐ์ดํ„ฐ ๋คํ”„๋ฅผ ์œ„ํ•ด etcd-client๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.

apt install etcd-client

2. etcdhelper๋ฅผ ๋นŒ๋“œํ•˜์‹ญ์‹œ์˜ค.

  • Golang์„ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค:
    GOPATH=/root/golang
    mkdir -p $GOPATH/local
    curl -sSL https://dl.google.com/go/go1.14.1.linux-amd64.tar.gz | tar -xzvC $GOPATH/local
    echo "export GOPATH="$GOPATH"" >> ~/.bashrc
    echo 'export GOROOT="$GOPATH/local/go"' >> ~/.bashrc
    echo 'export PATH="$PATH:$GOPATH/local/go/bin"' >> ~/.bashrc
  • ์šฐ๋ฆฌ๋Š” ์šฐ๋ฆฌ ์ž์‹ ์„ ์œ„ํ•ด ์ €์ถ•ํ•ฉ๋‹ˆ๋‹ค etcdhelper.go, ์ข…์†์„ฑ์„ ๋‹ค์šด๋กœ๋“œํ•˜๊ณ  ๋‹ค์Œ์„ ์ˆ˜์ง‘ํ•ฉ๋‹ˆ๋‹ค.
    wget https://raw.githubusercontent.com/flant/examples/master/2020/04-etcdhelper/etcdhelper.go
    go get go.etcd.io/etcd/clientv3 k8s.io/kubectl/pkg/scheme k8s.io/apimachinery/pkg/runtime
    go build -o etcdhelper etcdhelper.go

3. ๋ฐฑ์—… etcd๋ฅผ ๋งŒ๋“œ์‹ญ์‹œ์˜ค:

backup_dir=/root/backup
mkdir ${backup_dir}
cp -rL /etc/kubernetes ${backup_dir}
ETCDCTL_API=3 etcdctl --cacert=/etc/kubernetes/pki/etcd/ca.crt --key=/etc/kubernetes/pki/etcd/server.key --cert=/etc/kubernetes/pki/etcd/server.crt --endpoints https://192.168.199.100:2379 snapshot save ${backup_dir}/etcd.snapshot

4. Kubernetes ์ œ์–ด ํ”Œ๋ ˆ์ธ ๋งค๋‹ˆํŽ˜์ŠคํŠธ์—์„œ ์„œ๋น„์Šค ์„œ๋ธŒ๋„ท์„ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์ผ์—์„œ /etc/kubernetes/manifests/kube-apiserver.yaml ะธ /etc/kubernetes/manifests/kube-controller-manager.yaml ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•ด ๋ณด์„ธ์š” --service-cluster-ip-range ์ƒˆ ์„œ๋ธŒ๋„ท์œผ๋กœ: 172.24.0.0/16 ๋Œ€์‹  192.168.0.0/16.

5. kubeadm์ด apiserver์— ๋Œ€ํ•œ ์ธ์ฆ์„œ(ํฌํ•จ)๋ฅผ ๋ฐœ๊ธ‰ํ•˜๋Š” ์„œ๋น„์Šค ์„œ๋ธŒ๋„ท์„ ๋ณ€๊ฒฝํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์žฌ๋ฐœ๊ธ‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  1. ํ˜„์žฌ ์ธ์ฆ์„œ๊ฐ€ ๋ฐœ๊ธ‰๋œ ๋„๋ฉ”์ธ๊ณผ IP ์ฃผ์†Œ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
    openssl x509 -noout -ext subjectAltName </etc/kubernetes/pki/apiserver.crt
    X509v3 Subject Alternative Name:
        DNS:dev-1-master, DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, DNS:apiserver, IP Address:192.168.0.1, IP Address:10.0.0.163, IP Address:192.168.199.100
  2. kubeadm์— ๋Œ€ํ•œ ์ตœ์†Œ ๊ตฌ์„ฑ์„ ์ค€๋น„ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
    cat kubeadm-config.yaml
    apiVersion: kubeadm.k8s.io/v1beta1
    kind: ClusterConfiguration
    networking:
      podSubnet: "10.244.0.0/16"
      serviceSubnet: "172.24.0.0/16"
    apiServer:
      certSANs:
      - "192.168.199.100" # IP-ะฐะดั€ะตั ะผะฐัั‚ะตั€ ัƒะทะปะฐ
  3. ๊ธฐ์กด crt์™€ ํ‚ค๋ฅผ ์‚ญ์ œํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์‚ญ์ œํ•˜์ง€ ์•Š์œผ๋ฉด ์ƒˆ ์ธ์ฆ์„œ๊ฐ€ ๋ฐœ๊ธ‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    rm /etc/kubernetes/pki/apiserver.{key,crt}
  4. API ์„œ๋ฒ„์— ๋Œ€ํ•œ ์ธ์ฆ์„œ๋ฅผ ์žฌ๋ฐœ๊ธ‰ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
    kubeadm init phase certs apiserver --config=kubeadm-config.yaml
  5. ์ƒˆ ์„œ๋ธŒ๋„ท์— ๋Œ€ํ•ด ์ธ์ฆ์„œ๊ฐ€ ๋ฐœ๊ธ‰๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
    openssl x509 -noout -ext subjectAltName </etc/kubernetes/pki/apiserver.crt
    X509v3 Subject Alternative Name:
        DNS:kube-2-master, DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, IP Address:172.24.0.1, IP Address:10.0.0.163, IP Address:192.168.199.100
  6. API ์„œ๋ฒ„ ์ธ์ฆ์„œ๋ฅผ ๋‹ค์‹œ ๋ฐœ๊ธ‰ํ•œ ํ›„ ํ•ด๋‹น ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
    docker ps | grep k8s_kube-apiserver | awk '{print $1}' | xargs docker restart
  7. ๊ตฌ์„ฑ์„ ๋‹ค์‹œ ์ƒ์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. admin.conf:
    kubeadm alpha certs renew admin.conf
  8. etcd์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํŽธ์ง‘ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
    ./etcdhelper -cacert /etc/kubernetes/pki/etcd/ca.crt -cert /etc/kubernetes/pki/etcd/server.crt -key /etc/kubernetes/pki/etcd/server.key -endpoint https://127.0.0.1:2379 change-service-cidr 172.24.0.0/16 

    ๊ฒฝ๊ณ ! ํ˜„์žฌ ๊ธฐ์กด ํฌ๋“œ์—์„œ๋Š” ๋„๋ฉ”์ธ ํ™•์ธ์ด ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ์ž‘๋™์„ ์ค‘์ง€ํ•ฉ๋‹ˆ๋‹ค. /etc/resolv.conf ์ด์ „ CoreDNS ์ฃผ์†Œ(kube-dns)๊ฐ€ ๋“ฑ๋ก๋˜๊ณ  kube-proxy๋Š” iptables ๊ทœ์น™์„ ์ด์ „ ์„œ๋ธŒ๋„ท์—์„œ ์ƒˆ ์„œ๋ธŒ๋„ท์œผ๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์ด ๊ธฐ์‚ฌ์—์„œ๋Š” ๊ฐ€๋™ ์ค‘์ง€ ์‹œ๊ฐ„์„ ์ตœ์†Œํ™”ํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ€๋Šฅํ•œ ์˜ต์…˜์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

  9. ๋„ค์ž„์ŠคํŽ˜์ด์Šค์—์„œ ConfigMap์„ ์ˆ˜์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. kube-system:
    kubectl -n kube-system edit cm kubelet-config-1.16

    - ์—ฌ๊ธฐ์—์„œ ๊ต์ฒด clusterDNS kube-dns ์„œ๋น„์Šค์˜ ์ƒˆ IP ์ฃผ์†Œ๋กœ: kubectl -n kube-system get svc kube-dns.

    kubectl -n kube-system edit cm kubeadm-config

    - ์šฐ๋ฆฌ๊ฐ€ ๊ณ ์ณ์ค„๊ฒŒ data.ClusterConfiguration.networking.serviceSubnet ์ƒˆ ์„œ๋ธŒ๋„ท์œผ๋กœ.

  10. kube-dns ์ฃผ์†Œ๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์œผ๋ฏ€๋กœ ๋ชจ๋“  ๋…ธ๋“œ์—์„œ kubelet ๊ตฌ์„ฑ์„ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    kubeadm upgrade node phase kubelet-config && systemctl restart kubelet
  11. ๋‚จ์€ ๊ฒƒ์€ ํด๋Ÿฌ์Šคํ„ฐ์˜ ๋ชจ๋“  Pod๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
    kubectl get pods --no-headers=true --all-namespaces |sed -r 's/(S+)s+(S+).*/kubectl --namespace 1 delete pod 2/e'

๊ฐ€๋™ ์ค‘์ง€ ์‹œ๊ฐ„ ์ตœ์†Œํ™”

๊ฐ€๋™ ์ค‘์ง€ ์‹œ๊ฐ„์„ ์ตœ์†Œํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ƒ๊ฐ:

  1. ์ œ์–ด ํ”Œ๋ ˆ์ธ ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ๋ณ€๊ฒฝํ•œ ํ›„ ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜์—ฌ ์ƒˆ kube-dns ์„œ๋น„์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. kube-dns-tmp ๊ทธ๋ฆฌ๊ณ  ์ƒˆ ์ฃผ์†Œ 172.24.0.10.
  2. ํ™•์ธ if kube-dns ์„œ๋น„์Šค๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๋Š” etcdhelper์—์„œ.
  3. ๋ชจ๋“  kubelet์˜ ์ฃผ์†Œ๋ฅผ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค. ClusterDNS ์ด์ „ ์„œ๋น„์Šค๋Š” ์ƒˆ ์„œ๋น„์Šค์™€ ๋™์‹œ์— ๊ณ„์† ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.
  4. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ํฌํ•จ๋œ ํฌ๋“œ๊ฐ€ ์ž์—ฐ์Šค๋Ÿฌ์šด ์ด์œ ๋กœ ๋˜๋Š” ํ•ฉ์˜๋œ ์‹œ๊ฐ„์— ์ž๋™์œผ๋กœ ๋กค์˜ค๋ฒ„๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค.
  5. ์„œ๋น„์Šค ์‚ญ์ œ kube-dns-tmp ๊ทธ๋ฆฌ๊ณ  ๋ณ€ํ™” serviceSubnetCIDR kube-dns ์„œ๋น„์Šค์˜ ๊ฒฝ์šฐ.

์ด ๊ณ„ํš์„ ์‚ฌ์šฉํ•˜๋ฉด ์„œ๋น„์Šค ์ œ๊ฑฐ ๊ธฐ๊ฐ„ ๋™์•ˆ ๊ฐ€๋™ ์ค‘์ง€ ์‹œ๊ฐ„์„ ์ตœ๋Œ€ XNUMX๋ถ„์œผ๋กœ ์ตœ์†Œํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. kube-dns-tmp ์„œ๋น„์Šค์˜ ์„œ๋ธŒ๋„ท ๋ณ€๊ฒฝ kube-dns.

ํฌ๋“œ๋„คํŠธ์›Œํฌ ์ˆ˜์ •

๋™์‹œ์— ๊ฒฐ๊ณผ etcdhelper๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ podNetwork๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž‘์—… ์ˆœ์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ๊ตฌ์„ฑ ์ˆ˜์ • ์ค‘ kube-system;
  • kube-controller-manager ๋งค๋‹ˆํŽ˜์ŠคํŠธ ์ˆ˜์ •
  • etcd์—์„œ ์ง์ ‘ podCIDR์„ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.
  • ๋ชจ๋“  ํด๋Ÿฌ์Šคํ„ฐ ๋…ธ๋“œ๋ฅผ ์žฌ๋ถ€ํŒ…ํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ ์ด๋Ÿฌํ•œ ์ž‘์—…์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด์„ธ์š”.

1. ๋„ค์ž„์ŠคํŽ˜์ด์Šค์—์„œ ConfigMap ์ˆ˜์ • kube-system:

kubectl -n kube-system edit cm kubeadm-config

- ๊ต์ • data.ClusterConfiguration.networking.podSubnet ์ƒˆ ์„œ๋ธŒ๋„ท์œผ๋กœ 10.55.0.0/16.

kubectl -n kube-system edit cm kube-proxy

- ๊ต์ • data.config.conf.clusterCIDR: 10.55.0.0/16.

2. ์ปจํŠธ๋กค๋Ÿฌ-๊ด€๋ฆฌ์ž ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.

vim /etc/kubernetes/manifests/kube-controller-manager.yaml

- ๊ต์ • --cluster-cidr=10.55.0.0/16.

3. ํ˜„์žฌ ๊ฐ€์น˜๋ฅผ ์‚ดํŽด๋ณด์„ธ์š” .spec.podCIDR, .spec.podCIDRs, .InternalIP, .status.addresses ๋ชจ๋“  ํด๋Ÿฌ์Šคํ„ฐ ๋…ธ๋“œ์— ๋Œ€ํ•ด:

kubectl get no -o json | jq '[.items[] | {"name": .metadata.name, "podCIDR": .spec.podCIDR, "podCIDRs": .spec.podCIDRs, "InternalIP": (.status.addresses[] | select(.type == "InternalIP") | .address)}]'

[
  {
    "name": "kube-2-master",
    "podCIDR": "10.244.0.0/24",
    "podCIDRs": [
      "10.244.0.0/24"
    ],
    "InternalIP": "192.168.199.2"
  },
  {
    "name": "kube-2-master",
    "podCIDR": "10.244.0.0/24",
    "podCIDRs": [
      "10.244.0.0/24"
    ],
    "InternalIP": "10.0.1.239"
  },
  {
    "name": "kube-2-worker-01f438cf-579f9fd987-5l657",
    "podCIDR": "10.244.1.0/24",
    "podCIDRs": [
      "10.244.1.0/24"
    ],
    "InternalIP": "192.168.199.222"
  },
  {
    "name": "kube-2-worker-01f438cf-579f9fd987-5l657",
    "podCIDR": "10.244.1.0/24",
    "podCIDRs": [
      "10.244.1.0/24"
    ],
    "InternalIP": "10.0.4.73"
  }
]

4. etcd๋ฅผ ์ง์ ‘ ๋ณ€๊ฒฝํ•˜์—ฌ podCIDR์„ ๊ต์ฒดํ•ฉ๋‹ˆ๋‹ค.

./etcdhelper -cacert /etc/kubernetes/pki/etcd/ca.crt -cert /etc/kubernetes/pki/etcd/server.crt -key /etc/kubernetes/pki/etcd/server.key -endpoint https://127.0.0.1:2379 change-pod-cidr 10.55.0.0/16

5. podCIDR์ด ์‹ค์ œ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

kubectl get no -o json | jq '[.items[] | {"name": .metadata.name, "podCIDR": .spec.podCIDR, "podCIDRs": .spec.podCIDRs, "InternalIP": (.status.addresses[] | select(.type == "InternalIP") | .address)}]'

[
  {
    "name": "kube-2-master",
    "podCIDR": "10.55.0.0/24",
    "podCIDRs": [
      "10.55.0.0/24"
    ],
    "InternalIP": "192.168.199.2"
  },
  {
    "name": "kube-2-master",
    "podCIDR": "10.55.0.0/24",
    "podCIDRs": [
      "10.55.0.0/24"
    ],
    "InternalIP": "10.0.1.239"
  },
  {
    "name": "kube-2-worker-01f438cf-579f9fd987-5l657",
    "podCIDR": "10.55.1.0/24",
    "podCIDRs": [
      "10.55.1.0/24"
    ],
    "InternalIP": "192.168.199.222"
  },
  {
    "name": "kube-2-worker-01f438cf-579f9fd987-5l657",
    "podCIDR": "10.55.1.0/24",
    "podCIDRs": [
      "10.55.1.0/24"
    ],
    "InternalIP": "10.0.4.73"
  }
]

6. ๋ชจ๋“  ํด๋Ÿฌ์Šคํ„ฐ ๋…ธ๋“œ๋ฅผ ํ•˜๋‚˜์”ฉ ์žฌ๋ถ€ํŒ…ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

7. ํ•˜๋‚˜ ์ด์ƒ์˜ ๋…ธ๋“œ๋ฅผ ํƒˆํ‡ดํ•˜๋Š” ๊ฒฝ์šฐ ์ด์ „ PodCIDR, ๊ทธ๋Ÿฌ๋ฉด kube-controller-manager๋ฅผ ์‹œ์ž‘ํ•  ์ˆ˜ ์—†์œผ๋ฉฐ ํด๋Ÿฌ์Šคํ„ฐ์˜ Pod๊ฐ€ ์˜ˆ์•ฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์‹ค์ œ๋กœ podCIDR ๋ณ€๊ฒฝ์€ ํ›จ์”ฌ ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: ๊ทธ๋ž˜์„œ). ํ•˜์ง€๋งŒ etcd์—์„œ Kubernetes ๊ฐ์ฒด๋ฅผ ํŽธ์ง‘ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— etcd๋กœ ์ง์ ‘ ์ž‘์—…ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์šฐ๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹จ ํ•˜๋‚˜์˜ ๊ฐ€๋Šฅํ•œ ๋ณ€ํ˜•. (์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์šดํƒ€์ž„ ์—†์ด ์„œ๋น„์Šค ํ•„๋“œ๋งŒ ๋ณ€๊ฒฝํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. spec.clusterIP.)

ํ•ฉ๊ณ„

์ด ๊ธฐ์‚ฌ์—์„œ๋Š” etcd์˜ ๋ฐ์ดํ„ฐ๋กœ ์ง์ ‘ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅ์„ฑ์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. Kubernetes API๋ฅผ ์šฐํšŒํ•ฉ๋‹ˆ๋‹ค. ๋•Œ๋•Œ๋กœ ์ด ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด "๊นŒ๋‹ค๋กœ์šด ์ž‘์—…"์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ K8s ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ํ…์ŠคํŠธ์— ์ œ๊ณต๋œ ์ž‘์—…์„ ํ…Œ์ŠคํŠธํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋„๋ฆฌ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์ค€๋น„ ์ƒํƒœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. PoC(๊ฐœ๋… ์ฆ๋ช…). ๋”ฐ๋ผ์„œ ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ์ˆ˜์ •๋œ ๋ฒ„์ „์˜ etcdhelper ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ์ด์— ๋Œ€ํ•œ ์ฑ…์ž„์€ ์‚ฌ์šฉ์ž์—๊ฒŒ ์žˆ์Šต๋‹ˆ๋‹ค.

PS

๋ธ”๋กœ๊ทธ์—์„œ๋„ ์ฝ์–ด๋ณด์„ธ์š”.

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€