Docker ရဲ့ anti-pattern တချို့

Docker ကိုဘယ်လိုသုံးရမလဲ သိရမှာဖြစ်သလို တချိန်တည်းမှာပဲ Docker ကိုဘယ်လိုမသုံးရဘူးဆိုတာကိုလည်း နားလည်ထားဖို့ လိုပါတယ်။ ဒါမှသာ backfire မဖြစ်မှာပါ။

1) container image ထဲကို container အလုပ်လုပ်ဖို့ မလိုအပ်တဲ့ဟာ ဘာမှမထည့်ပါနဲ့။ ဒါမှ image ခပ်သေးသေးရမယ်။ ခပ်သေးသေး image တွေက attack surface နည်းတယ်။ image registry မှာ storage နေရာယူသက်သာမယ်။ server ကနေ လှမ်း pull တဲ့အခါ bandwidth သက်သာမယ်၊ ခပ်မြန်မြန် ရောက်မယ်။ ဒီတော့ linter တွေ၊ compiler တွေ၊ package manager တွေ၊ CLI နဲ့ test file တွေစသဖြင့် application functionality အတွက် မလိုအပ်တာတွေ မှန်သမျှ အကုန်ဖြုတ်ထားခဲ့ဖို့ လိုပါတယ်။ ဒီအတွက် multi-stage build ကိုသုံးတတ်အောင်သင်ပြီး image size ကိုသတိထားကြည့်တတ်ဖို့ အကျင့်လုပ်ပါ။

2) container image ဆောက်ဖို့ Dockerfile ရေးတဲ့အခါ cache hit ဖြစ်နိုင်သမျှ များများဖြစ်အောင် ရေးဖို့လိုပါတယ်။ Docker က layer-based ဖြစ်တဲ့အတွက် build process က layer အလိုက် cache ပါတယ်။ container build လုပ်တိုင်းမှာ checksum မကိုက်တဲ့ layer ကစပြီး တောက်လျှောက် cache မသုံးတော့တဲ့အတွက် တော်ရုံတန်ရုံ ပြောင်းလဲဖို့မရှိတဲ့ layer တွေကို build process ရဲ့အစောပိုင်းမှာ ထားဖို့လုပ်ရပါမယ်။ ဒါ့အပြင် Dockerfile ထဲက ဘယ် instruction တွေက layer တခုထွက်စေပြီး ဘယ်ဟာတွေက metadata ထပ်ပေါင်းရုံဖြစ်တယ်ဆိုတာ သိထားရပါမယ်။

3) Dockerfile တခုကို ဘယ်နှစ်ကြိမ် ပြန် run လိုက် run လိုက် build process ကတူညီတဲ့ output ကိုပဲ ပြန်ထုတ်ပေးနိုင်ရမယ်။ ဆိုလိုချင်တာက Dockerfile တခုကဘာ side effect မှမရှိရဘူး။ အဲဒီတော့ ကိုယ်သုံးထားတဲ့ base image တွေက immutable tag semantics ကိုပေးသလား သေချာအောင် လုပ်ဖို့လိုမယ်။ ရှိသမျှ software package တွေအကုန်လုံးကို version အတိအကျနဲ့ pin down လုပ်ဖို့လိုမယ်။ build process ထဲမှာ file တွေ download ဆွဲတာ၊ upload လုပ်တာ စသဖြင့်ကို ရှောင်ဖို့လိုမယ်။ ဒါတွေက CI ရဲ့တာဝန်ပါ။ Docker build process က CI pipeline မဟုတ်ပါဘူး။

4) နောက်တချက်က CI pipeline မှာ image တွေကို အခါခါ ပြန် build တာမျိုးမလုပ်ရပါဘူး။ app:v1.0.0 ကိုစိတ်ကျေနပ်လောက်အောင် test ပြီးသွားရင် အဲဒီ image ကိုပဲ staging နဲ့ production အတွက် promote ဖို့လိုပါတယ်။ နောက်တခါ ထပ် build လိုက်ခြင်းက resource ဖြုန်းတီးရာရောက်သလို ဒီ image ကစောစောက image နဲ့တထေရာတည်း တူပါတယ် အလုပ်ဖြစ်ပါမယ်ဆိုတဲ့ အာမခံမှုမျိုးလည်း မရှိတော့ပါဘူး။

5) image ကို ECS task definition, kustomize နဲ့ Helm chart တွေမှာသုံးတဲ့အခါ tag နဲ့ပဲ အလွယ်သတ်မှတ်လိုက်တာမျိုးကလည်း နောက်ထပ်ရှောင်ရမယ့် အကျင့်တခုပါ။ app:dev ဆိုတဲ့ tag က immutable မဟုတ်ပါဘူး။ တခြား process တခု pipeline တခုကနေ တခြား image version တခုအတွက် app:dev ဆိုတဲ့ tag ကိုပြန်သုံးပြီး registry ကို push လိုက်ရင် ကိုယ့် server environment က image တွေမှား pull မိတော့မှာပါ။ အဲဒီအတွက် image တိုင်းကို digest နဲ့ pin down လုပ်ထားဖို့လိုပါတယ်။

6) container process ကို မလိုအပ်ရင် container ရဲ့ root user နဲ့မ run ရပါဘူး။ container root user က host ရဲ့ root user မဟုတ်ပေမယ့် container ထဲမှာတော့ သူက root ဖြစ်တဲ့အတွက် container ရဲ့ filesystem, process tree စသဖြင့်တွေကို စိတ်ကြိုက်ထိန်းချုပ်နိုင်တယ်။ အဲဒါက confused deputy's problem တွေဖြစ်လာဖို့ လက်ယပ်ခေါ်နေတာနဲ့ အတူတူပါပဲ။ လုပ်လို့ရတာတခုက container process ကို non-root user နဲ့ run ပြီးအဲဒီ user ကိုလိုအပ်တဲ့ directory နဲ့ file permission တွေပေးထားလိုက်ဖို့ဖြစ်တယ်။

7) image ထဲမှာ ဘယ် package တွေသုံးထားတယ်၊ ဘယ် package တွေကတော့ဖြင့် CVE vulnerability ထွက်ထားတယ်ဆိုတာကို မစစ်တာကလည်း ရှောင်ရမယ့် နောက်ထပ်တချက်ပါ။ စစ်တယ်ဆိုတဲ့နေရာမှာလည်း build time မှာပဲ စစ်ရုံနဲ့မလုံလောက်ပါဘူး။ runtime မှာပါစစ်ဖို့ လိုအပ်ပါတယ်။ ဒါမှသာ ကိုယ့် environment ကအမြဲတမ်း လုံခြုံနေမယ်။

8) နောက်ထပ်မလုပ်ရမယ့်ဟာတခုက CI မှာ configuration parameter နဲ့ secret တွေကို Dockerfile ထဲ inject လုပ်ပြီး container image ဆောက်တာပါ။ CI pipeline ထဲကနေ AWS Secret Manager တို့ Vault တို့ကို လှမ်း query ပြီး ဒီလိုမျိုး static injection လုပ်လိုက်ခြင်းက application ကို statically configured ဖြစ်သွားစေတဲ့အတွက် မတူညီတဲ့ tuning တွေနဲ့ run လို့မရတော့သလို secret rotation တိုင်းမှာလည်း image ပြန် build ရတော့မှာဖြစ်တယ်။ ဒီအချက်က အပေါ်မှာပြောသွားတဲ့ နံပါတ် ၃ နဲ့လည်း ဖြောင့်ဖြောင့်ကြီး ဆန့်ကျင်နေတယ်။