Kubernetes руу Tinder шилжилт

Анхаарна уу. орчуулга.: Дэлхийд алдартай Tinder үйлчилгээний ажилтнууд саяхан Кубернетес рүү дэд бүтцээ шилжүүлэх техникийн зарим мэдээллийг хуваалцсан. Уг процесс нь бараг хоёр жил үргэлжилсэн бөгөөд 8 мянган чингэлэгт байрлуулсан 200 үйлчилгээнээс бүрдсэн K48 дээр маш том хэмжээний платформыг эхлүүлсэн. Tinder-ийн инженерүүд ямар сонирхолтой бэрхшээлтэй тулгарч, ямар үр дүнд хүрсэн бэ? Энэ орчуулгыг уншина уу.

Kubernetes руу Tinder шилжилт

Яагаад?

Бараг хоёр жилийн өмнө Tinder платформоо Кубернетес рүү шилжүүлэхээр шийджээ. Kubernetes нь Tinder-ийн багт хувиршгүй байршуулалтаар дамжуулан хамгийн бага хүчин чармайлтаар савлаж, үйлдвэрлэлд шилжих боломжийг олгоно. (өөрчлөгдөхгүй байршуулалт). Энэ тохиолдолд програмуудыг угсрах, тэдгээрийн байршуулалт, дэд бүтэц нь өөрөө кодоор тодорхойлогддог.

Мөн бид өргөтгөх чадвар, тогтвортой байдлын асуудлыг шийдэх гарцыг хайж байсан. Хэмжээг нэмэгдүүлэх нь чухал болсон үед бид шинэ EC2 инстанцуудыг эргүүлэх хүртэл хэдэн минут хүлээх шаардлагатай болдог. Контейнер хөөргөж, хэдэн минутын дотор замын хөдөлгөөнд оролцож эхлэх санаа нь бидний сонирхлыг татсан.

Процесс нь хэцүү байсан. 2019 оны эхээр бидний шилжилт хөдөлгөөний үеэр Кубернетес кластер маш чухал хэмжээнд хүрсэн бөгөөд бид хөдөлгөөний хэмжээ, кластерын хэмжээ, DNS зэргээс шалтгаалан янз бүрийн асуудалтай тулгарч эхэлсэн. Замдаа бид 200 үйлчилгээг шилжүүлэх, 1000 зангилаа, 15000 хонхорцог, 48000 ажиллаж байгаа контейнерээс бүрдсэн Кубернетес кластерыг ажиллуулахтай холбоотой олон сонирхолтой асуудлыг шийдсэн.

Яаж?

2018 оны нэгдүгээр сараас хойш бид шилжилт хөдөлгөөний янз бүрийн үе шатыг туулсан. Бид бүх үйлчилгээгээ багтааж, Kubernetes-ийн туршилтын үүлэн орчинд байршуулж эхэлсэн. XNUMX-р сараас эхлэн бид одоо байгаа бүх үйлчилгээг Кубернетес рүү шилжүүлж эхэлсэн. Дараа жилийн XNUMX-р сар гэхэд бид шилжилт хөдөлгөөнийг дуусгасан бөгөөд одоо Tinder платформ нь зөвхөн Kubernetes дээр ажиллаж байна.

Kubernetes-д зориулсан зураг бүтээх

Бид Kubernetes кластер дээр ажилладаг микро үйлчилгээний 30 гаруй эх кодын хадгалах газартай. Эдгээр агуулах дахь кодыг өөр хэл дээр (жишээлбэл, Node.js, Java, Scala, Go) бичсэн бөгөөд ижил хэлэнд зориулсан олон ажиллах орчинтой.

Бүтээлийн систем нь бичил үйлчилгээ тус бүрийг бүрэн өөрчлөх боломжтой "барилга угсралтын контекст"-ээр хангах зорилготой юм. Энэ нь ихэвчлэн Dockerfile болон бүрхүүлийн командуудын жагсаалтаас бүрдэнэ. Тэдгээрийн агуулгыг бүрэн тохируулах боломжтой бөгөөд үүний зэрэгцээ эдгээр бүх контекстийг стандартчилсан форматын дагуу бичдэг. Барилга угсралтын контекстийг стандартчилах нь бүх микро үйлчилгээг нэг бүтэцтэй системээр зохицуулах боломжийг олгодог.

Kubernetes руу Tinder шилжилт
Зураг 1-1. Builder контейнерээр дамжуулан стандартчилагдсан барилгын процесс

Ажиллах цагийн хооронд хамгийн их нийцтэй байдалд хүрэхийн тулд (ажиллуулах орчин) хөгжүүлэлт, туршилтын явцад ижил бүтээх процессыг ашигладаг. Бид маш сонирхолтой сорилттой тулгарсан: бид бүх платформ дээр бүтээх орчны тууштай байдлыг хангах арга замыг боловсруулах хэрэгтэй болсон. Үүнд хүрэхийн тулд угсрах бүх процессыг тусгай саванд хийдэг. Builder.

Түүний контейнерийн хэрэгжилт нь дэвшилтэт Docker техникийг шаарддаг. Builder нь хувийн Tinder репозиторуудад хандахад шаардлагатай дотоод хэрэглэгчийн ID болон нууцыг (SSH түлхүүр, AWS итгэмжлэл гэх мэт) өвлөн авдаг. Энэ нь угсралтын олдворуудыг байгалийн жамаар хадгалах эх сурвалжийг агуулсан орон нутгийн лавлахуудыг холбодог. Энэ арга нь Builder контейнер болон хостын хооронд бүтээх олдворуудыг хуулбарлах шаардлагагүй тул гүйцэтгэлийг сайжруулдаг. Хадгалсан бүтээх олдворуудыг нэмэлт тохиргоо хийлгүйгээр дахин ашиглах боломжтой.

Зарим үйлчилгээнүүдийн хувьд бид эмхэтгэлийн орчныг ажиллах үеийн орчинд буулгахын тулд өөр контейнер үүсгэх шаардлагатай болсон (жишээ нь, Node.js bcrypt номын сан нь суулгах явцад платформын тусгай хоёртын олдворуудыг үүсгэдэг). Эмхэтгэх явцад тавигдах шаардлага үйлчилгээнүүдийн хооронд харилцан адилгүй байж болох бөгөөд эцсийн Dockerfile нь шууд хөрвүүлэгддэг.

Kubernetes кластерын архитектур ба шилжилт хөдөлгөөн

Кластерын хэмжээг удирдах

Бид ашиглахаар шийдсэн kube-aws Amazon EC2 instance дээр автомат кластер байршуулахад зориулагдсан. Эхэндээ бүх зүйл зангилааны нэг нийтлэг санд ажилладаг байв. Нөөцийг илүү үр ашигтай ашиглахын тулд ажлын ачааллыг хэмжээ, жишээний төрлөөр нь ялгах шаардлагатайг бид хурдан ойлгосон. Логик нь хэд хэдэн ачаалал ихтэй олон урсгалтай подкуудыг ажиллуулах нь олон тооны нэг урсгалтай pods-уудтай зэрэгцэн оршихоос илүү гүйцэтгэлийн хувьд урьдчилан таамаглах боломжтой болсон.

Эцэст нь бид шийдсэн:

  • м5.4х том - мониторинг хийх (Прометей);
  • c5.4x том - Node.js ажлын ачаалал (нэг урсгалтай ажлын ачаалал);
  • c5.2x том - Java болон Go (олон урсгалтай ажлын ачаалал);
  • c5.4x том - хяналтын самбарын хувьд (3 зангилаа).

Шилжилт хөдөлгөөн

Хуучин дэд бүтцээс Кубернетес рүү шилжих бэлтгэлийн нэг алхам бол үйлчилгээнүүдийн хооронд байгаа шууд харилцааг шинэ ачаалал тэнцвэржүүлэгчид (Уян ачааллыг тэнцвэржүүлэгч (ELB)) руу шилжүүлэх явдал байв. Тэдгээр нь виртуал хувийн үүлэн (VPC) тодорхой дэд сүлжээнд үүсгэгдсэн. Энэ дэд сүлжээ нь Kubernetes VPC-тэй холбогдсон. Энэ нь үйлчилгээний хамаарлын тодорхой дарааллыг харгалзахгүйгээр модулиудыг аажмаар шилжүүлэх боломжийг бидэнд олгосон.

Эдгээр төгсгөлийн цэгүүд нь шинэ ELB бүрийг зааж буй CNAME бүхий DNS бичлэгүүдийн жигнэсэн багцыг ашиглан үүсгэгдсэн. Шилжүүлэхийн тулд бид 0 жинтэй Кубернетес үйлчилгээний шинэ ELB-г зааж буй шинэ оруулгыг нэмсэн. Дараа нь бид оруулгын амьдрах хугацааг (TTL) 0 болгож тохируулсан. Үүний дараа хуучин болон шинэ жингүүдийг тохируулсан. аажмаар тохируулж, эцэст нь ачааллын 100% шинэ сервер рүү илгээгдсэн. Шилжүүлэлт дууссаны дараа TTL утга илүү тохиромжтой түвшинд буцаж ирэв.

Бидэнд байсан Java модулиуд нь бага TTL DNS-ийг даван туулах чадвартай байсан ч Node програмууд үүнийг даван туулж чаддаггүй. Инженерүүдийн нэг нь холболтын сан кодын нэг хэсгийг дахин бичиж, 60 секунд тутамд усан сангуудыг шинэчилдэг менежерт ороосон. Сонгосон арга нь маш сайн ажилласан бөгөөд гүйцэтгэлийн мэдэгдэхүйц бууралтгүйгээр ажилласан.

Хичээлүүд

Сүлжээний даавууны хязгаар

8 оны 2019-р сарын XNUMX-ны өглөө эрт Tinder платформ гэнэт сүйрчээ. Тэр өглөө эрт платформын хоцролт хамааралгүй нэмэгдсэний хариуд кластер дахь хонхорцог болон зангилааны тоо нэмэгдсэн. Энэ нь манай бүх зангилаа дээр ARP кэшийг шавхахад хүргэсэн.

ARP кэштэй холбоотой гурван Linux сонголт байдаг:

Kubernetes руу Tinder шилжилт
(эх сурвалж)

gc_thresh3 - Энэ бол хатуу хязгаар юм. Бүртгэлд "хөршийн хүснэгт халих" бичилтүүд гарч ирсэн нь синхрон хог цуглуулах (GC) дараа ч хөрш оруулгыг хадгалахад ARP кэшэд хангалттай зай байхгүй гэсэн үг юм. Энэ тохиолдолд цөм нь пакетыг зүгээр л бүрэн хаясан.

Бидний хэрэглэдэг Flannel Kubernetes дахь сүлжээний даавуу болгон. Пакетуудыг VXLAN-аар дамжуулдаг. VXLAN бол L2 сүлжээний орой дээр босгосон L3 туннель юм. Энэхүү технологи нь MAC-in-UDP (MAC Address-in-User Datagram Protocol) капсулжуулалтыг ашигладаг бөгөөд 2-р түвшний сүлжээний сегментүүдийг өргөжүүлэх боломжийг олгодог. Физик өгөгдлийн төвийн сүлжээн дэх тээвэрлэлтийн протокол нь IP нэмэх UDP юм.

Kubernetes руу Tinder шилжилт
Зураг 2-1. Фланел диаграмм (эх сурвалж)

Kubernetes руу Tinder шилжилт
Зураг 2–2. VXLAN багц (эх сурвалж)

Kubernetes ажилчны зангилаа бүр том /24 блокоос /9 маск бүхий виртуал хаягийн зайг хуваарилдаг. Зангилаа бүрийн хувьд энэ нь байна гэсэн үг чиглүүлэлтийн хүснэгтэд нэг оруулга, ARP хүснэгтэд нэг оруулга (фланел.1 интерфэйс дээр), шилжих хүснэгтэд нэг оруулга (FDB). Ажилчны зангилаа анх эхлэхэд эсвэл шинэ зангилаа нээгдэх бүрт тэдгээрийг нэмдэг.

Нэмж дурдахад зангилаа (эсвэл pod-pod) холболт нь эцсийн эцэст интерфэйсээр дамждаг eth0 (дээрх Flannel диаграммд үзүүлсэн шиг). Үүний үр дүнд харгалзах эх сурвалж болон очих хост бүрийн ARP хүснэгтэд нэмэлт оруулга бий болно.

Манай орчинд энэ төрлийн харилцаа маш түгээмэл байдаг. Kubernetes дахь үйлчилгээний объектуудын хувьд ELB үүсгэгддэг бөгөөд Kubernetes нь зангилаа бүрийг ELB-д бүртгэдэг. ELB нь pods-ийн талаар юу ч мэдэхгүй бөгөөд сонгосон зангилаа нь багцын эцсийн цэг биш байж магадгүй юм. Гол нь зангилаа ELB-ээс пакет хүлээн авахдаа үүнийг дүрмийг харгалзан үздэг. iptables тодорхой үйлчилгээнд зориулж өөр зангилаа дээрх pod-ыг санамсаргүй байдлаар сонгоно.

Алдаа гарах үед кластерт 605 зангилаа байсан. Дээр дурдсан шалтгааны улмаас энэ нь ач холбогдлыг арилгахад хангалттай байсан gc_thresh3, энэ нь анхдагч юм. Ийм зүйл тохиолдоход пакетууд буурч эхлэхээс гадна /24 маск бүхий Flannel виртуал хаягийн орон зай ARP хүснэгтээс алга болно. Зангилааны холболт болон DNS асуулга тасалдсан (DNS нь кластерт байрладаг; дэлгэрэнгүйг энэ нийтлэлээс уншина уу).

Энэ асуудлыг шийдэхийн тулд та утгыг нэмэгдүүлэх хэрэгтэй gc_thresh1, gc_thresh2 и gc_thresh3 болон алга болсон сүлжээг дахин бүртгүүлэхийн тулд Flannel-ийг дахин эхлүүлнэ үү.

Гэнэтийн DNS масштаб

Шилжилтийн явцад бид DNS-ийг идэвхтэй ашиглаж урсгалыг удирдаж, үйлчилгээг хуучин дэд бүтцээс Кубернетес рүү аажмаар шилжүүлсэн. Бид Route53 дахь холбогдох RecordSets-ийн TTL утгыг харьцангуй бага тогтоосон. Хуучин дэд бүтэц нь EC2 инстанцууд дээр ажиллаж байх үед манай шийдүүлэгчийн тохиргоо Amazon DNS-ийг зааж өгсөн. Бид үүнийг энгийн зүйл гэж үзсэн бөгөөд манай үйлчилгээ болон Амазоны үйлчилгээнд (DynamoDB гэх мэт) бага TTL-ийн нөлөөг анзаарсангүй.

Бид үйлчилгээг Kubernetes руу шилжүүлэх явцад DNS секундэд 250 мянган хүсэлтийг боловсруулж байгааг олж мэдсэн. Үүний үр дүнд програмууд DNS асуулгад тогтмол бөгөөд ноцтой завсарлага авч эхэлсэн. Энэ нь DNS үйлчилгээ үзүүлэгчийг CoreDNS (оргил ачааллын үед 1000 цөм дээр ажилладаг 120 pod-д хүрсэн) болгон оновчтой болгох, өөрчлөх гайхалтай хүчин чармайлтыг үл харгалзан ийм зүйл болсон.

Бусад боломжит шалтгаан, шийдлүүдийг судалж байхдаа бид олж мэдсэн нийтлэл, пакет шүүлтүүрийн тогтолцоонд нөлөөлж буй уралдааны нөхцлийг тайлбарласан netfilter Линукс дээр. Бидний ажигласан цаг хугацаа, тоологч нэмэгдэж байна оруулах_амжилтгүй боллоо Flannel интерфэйс нь нийтлэлийн дүгнэлттэй нийцэж байсан.

Асуудал нь эх сурвалж ба очих сүлжээний хаягийн орчуулга (SNAT ба DNAT) болон дараа нь хүснэгтэд оруулах үе шатанд тохиолддог. холболт. Дотооддоо хэлэлцэж, олон нийтийн санал болгосон тойрон гарах арга замуудын нэг нь DNS-ийг ажилчны зангилаа руу шилжүүлэх явдал байв. Энэ тохиолдолд:

  • Траффик нь зангилаа дотор үлддэг тул SNAT шаардлагагүй. Үүнийг интерфейсээр дамжуулах шаардлагагүй eth0.
  • Очих газрын IP нь зангилааны локал бөгөөд дүрмийн дагуу санамсаргүй байдлаар сонгосон pod биш тул DNAT шаардлагагүй. iptables.

Бид энэ аргыг баримтлахаар шийдсэн. CoreDNS-ийг Kubernetes-д DaemonSet хэлбэрээр байрлуулсан бөгөөд бид дотоод зангилааны DNS серверийг хэрэгжүүлсэн. тогтоол тус бүрийг туг тавих замаар --cluster-dns баг кубелет . Энэ шийдэл нь DNS-ийн завсарлагааны хувьд үр дүнтэй болсон.

Гэсэн хэдий ч бид пакет алдагдаж, тоолуур нэмэгдсэнийг харсан оруулах_амжилтгүй боллоо Flannel интерфейс дээр. Бид зөвхөн DNS урсгалд зориулсан SNAT ба/эсвэл DNAT-г устгаж чадсан тул тойрч гарах шийдлийг хэрэгжүүлсний дараа энэ нь үргэлжилсэн. Бусад төрлийн хөдөлгөөнд уралдааны нөхцөлийг хадгалсан. Аз болоход манай пакетуудын ихэнх нь TCP бөгөөд хэрэв асуудал гарвал тэдгээрийг дахин дамжуулдаг. Бид бүх төрлийн замын хөдөлгөөнд тохирсон шийдлийг олохыг хичээсээр байна.

Ачааллыг илүү сайн тэнцвэржүүлэхийн тулд элчийг ашиглах

Бид арын үйлчилгээний үйлчилгээг Кубернетес рүү шилжүүлэхдээ подкуудын хооронд тэнцвэргүй ачааллаас болж зовж эхэлсэн. Бид HTTP Keepalive нь ELB холболтуудыг байршуулалт бүрийн эхний бэлэн pods дээр өлгөхөд хүргэсэн болохыг олж мэдсэн. Тиймээс замын хөдөлгөөний дийлэнх хэсэг нь бэлэн байгаа pods-ийн багахан хувийг эзэлдэг. Бидний туршиж үзсэн хамгийн эхний шийдэл бол хамгийн муу тохиолдлын хувилбаруудад MaxSurge-г 100% болгон шинэ байршуулалтад тохируулах явдал байв. Үр нөлөө нь илүү том байршуулалтын хувьд ач холбогдолгүй бөгөөд ирээдүйгүй болсон.

Бидний ашигласан өөр нэг шийдэл бол чухал үйлчилгээний нөөцийн хүсэлтийг зохиомлоор нэмэгдүүлэх явдал байв. Энэ тохиолдолд ойролцоо байрлуулсан хонхорцог бусад хүнд хонхорцогтой харьцуулахад маневр хийх илүү зайтай байх болно. Энэ нь урт хугацаанд бас үр дүнгүй, учир нь энэ нь нөөцийг дэмий үрэх болно. Нэмж дурдахад манай Node програмууд нь нэг урсгалтай байсан бөгөөд үүний дагуу зөвхөн нэг цөм ашиглах боломжтой байв. Цорын ганц бодит шийдэл бол илүү сайн ачааллын тэнцвэрийг ашиглах явдал байв.

Бид бүрэн дүүрэн үнэлэхийг эртнээс хүсч байсан элч. Одоогийн нөхцөл байдал нь үүнийг маш хязгаарлагдмал байдлаар байрлуулж, шууд үр дүнд хүрэх боломжийг бидэнд олгосон. Envoy нь том SOA програмуудад зориулагдсан өндөр хүчин чадалтай, нээлттэй эх сурвалжтай, давхарга-XNUMX прокси юм. Энэ нь автомат дахин оролдлого, таслуур, дэлхийн хурдыг хязгаарлах зэрэг ачааллын тэнцвэржүүлэх дэвшилтэт техникийг хэрэгжүүлж чадна. (Анхаарна уу. орчуулга.: Та энэ талаар дэлгэрэнгүй унших боломжтой энэ нийтлэл Элч дээр үндэслэсэн Истиогийн тухай.)

Бид дараах тохиргоог хийсэн: под тус бүрт Envoy хажуугийн тэрэг, нэг маршруттай байх ба кластерийг портоор дамжуулан контейнерт холбоно. Боломжит шатлалыг багасгаж, бага хэмжээний цохилтын радиусыг хадгалахын тулд бид үйлчилгээ тус бүрд Availability Zone (AZ) тус бүрээр Envoy front-proxy pods-ийн флотыг ашигласан. Тэд манай нэг инженерийн бичсэн энгийн үйлчилгээний нээлтийн хөдөлгүүрт тулгуурласан бөгөөд энэ нь тухайн үйлчилгээнд зориулж AZ тус бүр дэх хонхорцогуудын жагсаалтыг буцаасан.

Үйлчилгээний фронтын элч нар дараа нь энэ үйлчилгээг илрүүлэх механизмыг дээд урсгалын нэг кластер болон маршрутаар ашигласан. Бид хангалттай хугацаа тогтоож, таслагчийн бүх тохиргоог нэмэгдүүлж, нэг удаагийн эвдрэлийг арилгахад туслах, жигд байрлуулалтыг хангахын тулд дахин оролдох хамгийн бага тохиргоог нэмсэн. Бид эдгээр үйлчилгээний фронтын элч бүрийн өмнө TCP ELB байрлуулсан. Манай үндсэн прокси давхаргын хадгалалт нь зарим Envoy pod-д наалдсан байсан ч тэдгээр нь ачааллыг илүү сайн даван туулж, арын хэсэгт хамгийн бага_хүсэлтээр тэнцвэржүүлэхээр тохируулагдсан.

Байршуулахын тулд бид preStop дэгээг програмын тавиур болон хажуугийн тавиур дээр ашигласан. Уг дэгээ нь хажуугийн тавиур дээр байрлах админ төгсгөлийн цэгийн статусыг шалгахад алдаа гаргаж, идэвхтэй холболтыг зогсоохын тулд хэсэг хугацаанд унтсан.

Бидний ийм хурдан хөдөлж чадсан шалтгаануудын нэг нь ердийн Prometheus суулгацтай хялбархан нэгтгэж чадсан нарийвчилсан хэмжүүрүүдтэй холбоотой юм. Энэ нь тохиргооны параметрүүдийг тохируулж, урсгалыг дахин хуваарилах үед яг юу болж байгааг харах боломжийг бидэнд олгосон.

Үр дүн нь шууд бөгөөд ойлгомжтой байсан. Бид хамгийн тэнцвэргүй үйлчилгээгээр эхэлсэн бөгөөд одоогоор энэ нь кластерийн хамгийн чухал 12 үйлчилгээний өмнө ажиллаж байна. Энэ жил бид илүү дэвшилтэт үйлчилгээний нээлт, хэлхээг таслах, хэт утгыг илрүүлэх, хурдыг хязгаарлах, хянах зэрэг бүрэн үйлчилгээний сүлжээнд шилжихээр төлөвлөж байна.

Kubernetes руу Tinder шилжилт
Зураг 3-1. Envoy руу шилжих үед нэг үйлчилгээний CPU-ийн нэгдэл

Kubernetes руу Tinder шилжилт

Kubernetes руу Tinder шилжилт

Эцсийн үр дүн

Энэхүү туршлага, нэмэлт судалгааны үр дүнд бид Кубернетесийн томоохон кластеруудыг төлөвлөх, байршуулах, ажиллуулах ур чадвар бүхий хүчирхэг дэд бүтцийн багийг бүрдүүлсэн. Tinder-ийн бүх инженерүүд одоо сав баглаа боодол, Kubernetes-д програмуудыг байрлуулах мэдлэг, туршлагатай болсон.

Хуучин дэд бүтцэд нэмэлт хүчин чадал шаардагдах үед бид шинэ EC2 инстанцуудыг эхлүүлэх хүртэл хэдэн минут хүлээх шаардлагатай болсон. Одоо чингэлэгүүд ажиллаж эхэлж, хэдэн минутын дотор урсгалыг боловсруулж эхэлдэг. Нэг EC2 инстанц дээр олон савыг төлөвлөх нь хэвтээ концентрацийг сайжруулдаг. Үүний үр дүнд бид 2019 онд EC2 зардлыг өнгөрсөн жилтэй харьцуулахад мэдэгдэхүйц буурна гэж таамаглаж байна.

Шилжилт хөдөлгөөн бараг хоёр жил үргэлжилсэн ч бид 2019 оны гуравдугаар сард дуусгасан. Одоогоор Tinder платформ нь зөвхөн 200 үйлчилгээ, 1000 зангилаа, 15 хонхорцог, 000 ажилладаг контейнерээс бүрдсэн Kubernetes кластер дээр ажилладаг. Дэд бүтэц нь үйл ажиллагааны багуудын цорын ганц салбар байхаа больсон. Манай бүх инженерүүд энэ хариуцлагыг хуваалцаж, зөвхөн код ашиглан програмуудаа бүтээх, байршуулах үйл явцыг хянадаг.

Орчуулагчийн жич

Мөн манай блог дээрх цуврал нийтлэлүүдийг уншина уу:

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх