[{"data":1,"prerenderedAt":1905},["ShallowReactive",2],{"article-\u002Farticles\u002Fcontainerd-and-nerdctl":3},{"id":4,"title":5,"body":6,"date":1893,"description":292,"excerpt":1894,"extension":1895,"meta":1896,"navigation":385,"path":1897,"seo":1898,"stem":1899,"tags":1900,"__hash__":1904},"articles\u002Farticles\u002Fcontainerd-and-nerdctl.md","從 Docker 換到 containerd + nerdctl：架構差異、安裝 runc 與 CNI，以及移除 Docker 後的網路問題",{"type":7,"value":8,"toc":1865},"minimark",[9,14,18,35,46,50,57,65,144,155,158,176,180,183,252,270,274,279,286,462,465,479,503,506,511,593,597,606,618,621,636,647,727,744,748,768,860,882,886,895,913,1006,1012,1015,1063,1067,1070,1073,1102,1105,1116,1145,1176,1183,1187,1190,1274,1278,1281,1287,1308,1316,1319,1325,1360,1373,1376,1379,1384,1389,1420,1425,1483,1488,1505,1583,1609,1614,1665,1685,1690,1788,1799,1802,1826,1829,1852,1855,1861],[10,11,13],"h2",{"id":12},"為什麼不用-docker-了","為什麼不用 Docker 了",[15,16,17],"p",{},"以前部署容器，第一步一定是裝 Docker。但這次換掉它有兩個原因：",[19,20,21,29],"ul",{},[22,23,24,28],"li",{},[25,26,27],"strong",{},"Docker 太肥大了","：這些主機只需要「拉映像檔、跑容器」，Docker 卻附帶了 dockerd 常駐程式、自己的網路與儲存管理、Swarm 等一整套功能，多一層元件就多一份要維護、要更新、要擔心的東西",[22,30,31,34],{},[25,32,33],{},"和公司的 Harbor 不相容","：公司的 Harbor 一直沒有升版，在我們的環境裡，安裝 docker-ce 18.06 以上的版本就無法從 Harbor 拉取映像檔。但為了配合舊的 Harbor 一直停在舊版 Docker，也不是長久之計",[15,36,37,38,41,42,45],{},"而 Docker 底層真正在管理容器的，其實就是 ",[25,39,40],{},"containerd","。Kubernetes 從 1.24 開始移除了 dockershim，也已經直接使用 containerd 這類 CRI 執行環境。所以只要把 Docker 拿掉、直接用 containerd，再搭配一個指令和 Docker 幾乎一樣的 CLI——",[25,43,44],{},"nerdctl","——就能用更少的元件做到一樣的事。",[10,47,49],{"id":48},"docker-和-containerd-是什麼關係","Docker 和 containerd 是什麼關係",[15,51,52],{},[53,54],"img",{"alt":55,"src":56},"Docker 與 containerd + nerdctl 的架構比較：使用 Docker 時，docker CLI 呼叫常駐的 dockerd，dockerd 再呼叫 containerd，由 containerd-shim 啟動 runc 建立容器，網路由 dockerd 自己管理 docker0 橋接網卡與 iptables 規則；改用 nerdctl 後，nerdctl 直接呼叫 containerd，少了 dockerd 這一層，容器同樣由 containerd-shim 與 runc 建立，網路則交給 CNI plugins 建立 nerdctl0 橋接網卡與 iptables 規則；Kubernetes 的 kubelet 也是透過 CRI 直接呼叫同一個 containerd","\u002Fimages\u002Farticles\u002Fcontainerd-architecture.svg",[15,58,59,60,64],{},"一個 ",[61,62,63],"code",{},"docker run"," 背後其實經過好幾層：",[66,67,68,81],"table",{},[69,70,71],"thead",{},[72,73,74,78],"tr",{},[75,76,77],"th",{},"元件",[75,79,80],{},"負責什麼",[82,83,84,95,105,114,124,134],"tbody",{},[72,85,86,92],{},[87,88,89],"td",{},[25,90,91],{},"docker CLI",[87,93,94],{},"使用者下指令的工具",[72,96,97,102],{},[87,98,99],{},[25,100,101],{},"dockerd",[87,103,104],{},"Docker 的常駐程式，處理 API、建置映像檔、管理網路與 Volume",[72,106,107,111],{},[87,108,109],{},[25,110,40],{},[87,112,113],{},"管理容器的生命週期：拉映像檔、管理快照、建立與監控容器",[72,115,116,121],{},[87,117,118],{},[25,119,120],{},"containerd-shim",[87,122,123],{},"每個容器一個，讓 containerd 重啟時容器不會跟著停",[72,125,126,131],{},[87,127,128],{},[25,129,130],{},"runc",[87,132,133],{},"真正呼叫 Linux 核心（namespace、cgroups）建立容器的低階執行環境，遵循 OCI 規範",[72,135,136,141],{},[87,137,138],{},[25,139,140],{},"CNI plugins",[87,142,143],{},"負責容器的網路：建立橋接網卡、分配 IP、設定 Port 對應",[15,145,146,147,150,151,154],{},"改用 containerd + nerdctl 之後，",[25,148,149],{},"dockerd 這一層就不見了","，nerdctl 直接呼叫 containerd。容器的建立方式完全一樣，還是 containerd-shim 加 runc；差別在於網路：Docker 的網路是 dockerd 自己管的，",[25,152,153],{},"containerd 本身不管網路","，所以要另外安裝 CNI plugins，由 nerdctl 呼叫它們來建立網路。",[15,156,157],{},"這也是安裝時需要三樣東西的原因：",[159,160,161,166,171],"ol",{},[22,162,163,165],{},[25,164,40],{},"：管理容器",[22,167,168,170],{},[25,169,130],{},"：建立容器",[22,172,173,175],{},[25,174,140],{},"：容器網路",[10,177,179],{"id":178},"和-containerd-互動的三種-cli","和 containerd 互動的三種 CLI",[15,181,182],{},"containerd 有三種常見的命令列工具，用途不同：",[66,184,185,198],{},[69,186,187],{},[72,188,189,192,195],{},[75,190,191],{},"工具",[75,193,194],{},"定位",[75,196,197],{},"適合",[82,199,200,213,226],{},[72,201,202,207,210],{},[87,203,204],{},[61,205,206],{},"ctr",[87,208,209],{},"containerd 內建的除錯工具",[87,211,212],{},"低階除錯，指令和 Docker 差很多，也不處理網路",[72,214,215,220,223],{},[87,216,217],{},[61,218,219],{},"crictl",[87,221,222],{},"透過 CRI 介面操作，是給 Kubernetes 用的",[87,224,225],{},"在 K8s 節點上查看 kubelet 建立的 Pod 與容器",[72,227,228,232,235],{},[87,229,230],{},[61,231,44],{},[87,233,234],{},"和 Docker CLI 相容的工具",[87,236,237,240,241,244,245,244,248,251],{},[25,238,239],{},"取代 docker 指令","，支援 ",[61,242,243],{},"run -p","、",[61,246,247],{},"compose",[61,249,250],{},"login"," 等",[15,253,254,255,257,258,261,262,265,266,269],{},"日常使用選 nerdctl 就對了：",[61,256,63],{}," 改成 ",[61,259,260],{},"nerdctl run","，大部分的參數都一樣，連 ",[61,263,264],{},"nerdctl compose up"," 都可以直接吃原本的 ",[61,267,268],{},"docker-compose.yml","。",[10,271,273],{"id":272},"安裝-containerd","安裝 containerd",[275,276,278],"h3",{"id":277},"加入-docker-的-apt-套件庫","加入 Docker 的 apt 套件庫",[15,280,281,282,285],{},"containerd 的 ",[61,283,284],{},"containerd.io"," 套件是由 Docker 的 apt 套件庫提供的，先加入金鑰與套件庫：",[287,288,293],"pre",{"className":289,"code":290,"language":291,"meta":292,"style":292},"language-bash shiki shiki-themes github-dark","sudo apt-get update\nsudo apt-get install ca-certificates curl\nsudo install -m 0755 -d \u002Fetc\u002Fapt\u002Fkeyrings\nsudo curl -fsSL https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fubuntu\u002Fgpg -o \u002Fetc\u002Fapt\u002Fkeyrings\u002Fdocker.asc\nsudo chmod a+r \u002Fetc\u002Fapt\u002Fkeyrings\u002Fdocker.asc\n\necho \\\n  \"deb [arch=$(dpkg --print-architecture) signed-by=\u002Fetc\u002Fapt\u002Fkeyrings\u002Fdocker.asc] https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fubuntu \\\n  $(. \u002Fetc\u002Fos-release && echo \"$VERSION_CODENAME\") stable\" | \\\n  sudo tee \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fdocker.list > \u002Fdev\u002Fnull\n","bash","",[61,294,295,311,327,347,367,380,387,396,414,444],{"__ignoreMap":292},[296,297,300,304,308],"span",{"class":298,"line":299},"line",1,[296,301,303],{"class":302},"svObZ","sudo",[296,305,307],{"class":306},"sU2Wk"," apt-get",[296,309,310],{"class":306}," update\n",[296,312,314,316,318,321,324],{"class":298,"line":313},2,[296,315,303],{"class":302},[296,317,307],{"class":306},[296,319,320],{"class":306}," install",[296,322,323],{"class":306}," ca-certificates",[296,325,326],{"class":306}," curl\n",[296,328,330,332,334,338,341,344],{"class":298,"line":329},3,[296,331,303],{"class":302},[296,333,320],{"class":306},[296,335,337],{"class":336},"sDLfK"," -m",[296,339,340],{"class":336}," 0755",[296,342,343],{"class":336}," -d",[296,345,346],{"class":306}," \u002Fetc\u002Fapt\u002Fkeyrings\n",[296,348,350,352,355,358,361,364],{"class":298,"line":349},4,[296,351,303],{"class":302},[296,353,354],{"class":306}," curl",[296,356,357],{"class":336}," -fsSL",[296,359,360],{"class":306}," https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fubuntu\u002Fgpg",[296,362,363],{"class":336}," -o",[296,365,366],{"class":306}," \u002Fetc\u002Fapt\u002Fkeyrings\u002Fdocker.asc\n",[296,368,370,372,375,378],{"class":298,"line":369},5,[296,371,303],{"class":302},[296,373,374],{"class":306}," chmod",[296,376,377],{"class":306}," a+r",[296,379,366],{"class":306},[296,381,383],{"class":298,"line":382},6,[296,384,386],{"emptyLinePlaceholder":385},true,"\n",[296,388,390,393],{"class":298,"line":389},7,[296,391,392],{"class":336},"echo",[296,394,395],{"class":336}," \\\n",[296,397,399,402,405,408,411],{"class":298,"line":398},8,[296,400,401],{"class":306},"  \"deb [arch=$(",[296,403,404],{"class":302},"dpkg",[296,406,407],{"class":336}," --print-architecture",[296,409,410],{"class":306},") signed-by=\u002Fetc\u002Fapt\u002Fkeyrings\u002Fdocker.asc] https:\u002F\u002Fdownload.docker.com\u002Flinux\u002Fubuntu ",[296,412,413],{"class":336},"\\\n",[296,415,417,420,423,426,428,431,435,438,442],{"class":298,"line":416},9,[296,418,419],{"class":306},"  $(",[296,421,422],{"class":336},".",[296,424,425],{"class":306}," \u002Fetc\u002Fos-release && ",[296,427,392],{"class":336},[296,429,430],{"class":306}," \"",[296,432,434],{"class":433},"s95oV","$VERSION_CODENAME",[296,436,437],{"class":306},"\") stable\"",[296,439,441],{"class":440},"snl16"," |",[296,443,395],{"class":336},[296,445,447,450,453,456,459],{"class":298,"line":446},10,[296,448,449],{"class":302},"  sudo",[296,451,452],{"class":306}," tee",[296,454,455],{"class":306}," \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fdocker.list",[296,457,458],{"class":440}," >",[296,460,461],{"class":306}," \u002Fdev\u002Fnull\n",[275,463,273],{"id":464},"安裝-containerd-1",[15,466,467,468,470,471,474,475,478],{},"只安裝 ",[61,469,284],{},"，",[25,472,473],{},"不要","安裝 ",[61,476,477],{},"docker-ce","：",[287,480,482],{"className":289,"code":481,"language":291,"meta":292,"style":292},"sudo apt-get update\nsudo apt-get install containerd.io\n",[61,483,484,492],{"__ignoreMap":292},[296,485,486,488,490],{"class":298,"line":299},[296,487,303],{"class":302},[296,489,307],{"class":306},[296,491,310],{"class":306},[296,493,494,496,498,500],{"class":298,"line":313},[296,495,303],{"class":302},[296,497,307],{"class":306},[296,499,320],{"class":306},[296,501,502],{"class":306}," containerd.io\n",[275,504,505],{"id":505},"產生設定檔並啟動",[15,507,508,510],{},[61,509,284],{}," 附的設定檔是給 Docker 用的精簡版，建議改用 containerd 的完整預設設定，之後要調整 Registry、cgroup 等設定才有地方改：",[287,512,514],{"className":289,"code":513,"language":291,"meta":292,"style":292},"sudo mkdir -p \u002Fetc\u002Fcontainerd\ncontainerd config default | sudo tee \u002Fetc\u002Fcontainerd\u002Fconfig.toml > \u002Fdev\u002Fnull\n\nsudo systemctl daemon-reload\nsudo systemctl enable --now containerd\nsudo systemctl status containerd\n",[61,515,516,529,553,557,567,582],{"__ignoreMap":292},[296,517,518,520,523,526],{"class":298,"line":299},[296,519,303],{"class":302},[296,521,522],{"class":306}," mkdir",[296,524,525],{"class":336}," -p",[296,527,528],{"class":306}," \u002Fetc\u002Fcontainerd\n",[296,530,531,533,536,539,541,544,546,549,551],{"class":298,"line":313},[296,532,40],{"class":302},[296,534,535],{"class":306}," config",[296,537,538],{"class":306}," default",[296,540,441],{"class":440},[296,542,543],{"class":302}," sudo",[296,545,452],{"class":306},[296,547,548],{"class":306}," \u002Fetc\u002Fcontainerd\u002Fconfig.toml",[296,550,458],{"class":440},[296,552,461],{"class":306},[296,554,555],{"class":298,"line":329},[296,556,386],{"emptyLinePlaceholder":385},[296,558,559,561,564],{"class":298,"line":349},[296,560,303],{"class":302},[296,562,563],{"class":306}," systemctl",[296,565,566],{"class":306}," daemon-reload\n",[296,568,569,571,573,576,579],{"class":298,"line":369},[296,570,303],{"class":302},[296,572,563],{"class":306},[296,574,575],{"class":306}," enable",[296,577,578],{"class":336}," --now",[296,580,581],{"class":306}," containerd\n",[296,583,584,586,588,591],{"class":298,"line":382},[296,585,303],{"class":302},[296,587,563],{"class":306},[296,589,590],{"class":306}," status",[296,592,581],{"class":306},[10,594,596],{"id":595},"安裝-runc","安裝 runc",[15,598,599,601,602,605],{},[61,600,284],{}," 套件其實",[25,603,604],{},"已經附帶了 runc","，可以先確認：",[287,607,609],{"className":289,"code":608,"language":291,"meta":292,"style":292},"runc --version\n",[61,610,611],{"__ignoreMap":292},[296,612,613,615],{"class":298,"line":299},[296,614,130],{"class":302},[296,616,617],{"class":336}," --version\n",[15,619,620],{},"如果是從 GitHub 下載 containerd 的二進位檔安裝（不透過 apt），或是需要更新 runc 版本，再手動安裝。先確認系統架構：",[287,622,624],{"className":289,"code":623,"language":291,"meta":292,"style":292},"dpkg --print-architecture   # 例如 amd64、arm64\n",[61,625,626],{"__ignoreMap":292},[296,627,628,630,632],{"class":298,"line":299},[296,629,404],{"class":302},[296,631,407],{"class":336},[296,633,635],{"class":634},"sAwPA","   # 例如 amd64、arm64\n",[15,637,638,639,646],{},"再到 ",[640,641,645],"a",{"href":642,"rel":643},"https:\u002F\u002Fgithub.com\u002Fopencontainers\u002Frunc\u002Freleases",[644],"nofollow","runc Releases"," 選擇版本下載：",[287,648,650],{"className":289,"code":649,"language":291,"meta":292,"style":292},"RUNC_VERSION=1.1.12\nARCH=$(dpkg --print-architecture)\n\nwget https:\u002F\u002Fgithub.com\u002Fopencontainers\u002Frunc\u002Freleases\u002Fdownload\u002Fv${RUNC_VERSION}\u002Frunc.${ARCH}\nsudo install -m 755 runc.${ARCH} \u002Fusr\u002Flocal\u002Fsbin\u002Frunc\nrunc --version\n",[61,651,652,663,680,684,701,721],{"__ignoreMap":292},[296,653,654,657,660],{"class":298,"line":299},[296,655,656],{"class":433},"RUNC_VERSION",[296,658,659],{"class":440},"=",[296,661,662],{"class":306},"1.1.12\n",[296,664,665,668,670,673,675,677],{"class":298,"line":313},[296,666,667],{"class":433},"ARCH",[296,669,659],{"class":440},[296,671,672],{"class":433},"$(",[296,674,404],{"class":302},[296,676,407],{"class":336},[296,678,679],{"class":433},")\n",[296,681,682],{"class":298,"line":329},[296,683,386],{"emptyLinePlaceholder":385},[296,685,686,689,692,695,698],{"class":298,"line":349},[296,687,688],{"class":302},"wget",[296,690,691],{"class":306}," https:\u002F\u002Fgithub.com\u002Fopencontainers\u002Frunc\u002Freleases\u002Fdownload\u002Fv",[296,693,694],{"class":433},"${RUNC_VERSION}",[296,696,697],{"class":306},"\u002Frunc.",[296,699,700],{"class":433},"${ARCH}\n",[296,702,703,705,707,709,712,715,718],{"class":298,"line":369},[296,704,303],{"class":302},[296,706,320],{"class":306},[296,708,337],{"class":336},[296,710,711],{"class":336}," 755",[296,713,714],{"class":306}," runc.",[296,716,717],{"class":433},"${ARCH} ",[296,719,720],{"class":306},"\u002Fusr\u002Flocal\u002Fsbin\u002Frunc\n",[296,722,723,725],{"class":298,"line":382},[296,724,130],{"class":302},[296,726,617],{"class":336},[728,729,730],"blockquote",{},[15,731,732,733,736,737,740,741,743],{},"Releases 頁面上也會列出 ",[61,734,735],{},"-rc"," 結尾的預覽版本（例如 ",[61,738,739],{},"v1.2.0-rc.1","），正式環境請選擇沒有 ",[61,742,735],{}," 的穩定版。",[10,745,747],{"id":746},"安裝-cni-plugins","安裝 CNI plugins",[15,749,750,751,754,755,757,758,761,762,767],{},"containerd 不管網路，",[61,752,753],{},"nerdctl run -p 8080:80"," 這種 Port 對應、容器之間的網路，都是由 CNI plugins 處理。",[61,756,284],{}," ",[25,759,760],{},"沒有","附帶 CNI，一定要自己安裝，到 ",[640,763,766],{"href":764,"rel":765},"https:\u002F\u002Fgithub.com\u002Fcontainernetworking\u002Fplugins\u002Freleases",[644],"CNI plugins Releases"," 選擇版本：",[287,769,771],{"className":289,"code":770,"language":291,"meta":292,"style":292},"CNI_VERSION=1.5.0\nARCH=$(dpkg --print-architecture)\n\nwget https:\u002F\u002Fgithub.com\u002Fcontainernetworking\u002Fplugins\u002Freleases\u002Fdownload\u002Fv${CNI_VERSION}\u002Fcni-plugins-linux-${ARCH}-v${CNI_VERSION}.tgz\nsudo mkdir -p \u002Fopt\u002Fcni\u002Fbin\nsudo tar Cxzvf \u002Fopt\u002Fcni\u002Fbin cni-plugins-linux-${ARCH}-v${CNI_VERSION}.tgz\n",[61,772,773,783,797,801,825,836],{"__ignoreMap":292},[296,774,775,778,780],{"class":298,"line":299},[296,776,777],{"class":433},"CNI_VERSION",[296,779,659],{"class":440},[296,781,782],{"class":306},"1.5.0\n",[296,784,785,787,789,791,793,795],{"class":298,"line":313},[296,786,667],{"class":433},[296,788,659],{"class":440},[296,790,672],{"class":433},[296,792,404],{"class":302},[296,794,407],{"class":336},[296,796,679],{"class":433},[296,798,799],{"class":298,"line":329},[296,800,386],{"emptyLinePlaceholder":385},[296,802,803,805,808,811,814,817,820,822],{"class":298,"line":349},[296,804,688],{"class":302},[296,806,807],{"class":306}," https:\u002F\u002Fgithub.com\u002Fcontainernetworking\u002Fplugins\u002Freleases\u002Fdownload\u002Fv",[296,809,810],{"class":433},"${CNI_VERSION}",[296,812,813],{"class":306},"\u002Fcni-plugins-linux-",[296,815,816],{"class":433},"${ARCH}",[296,818,819],{"class":306},"-v",[296,821,810],{"class":433},[296,823,824],{"class":306},".tgz\n",[296,826,827,829,831,833],{"class":298,"line":369},[296,828,303],{"class":302},[296,830,522],{"class":306},[296,832,525],{"class":336},[296,834,835],{"class":306}," \u002Fopt\u002Fcni\u002Fbin\n",[296,837,838,840,843,846,849,852,854,856,858],{"class":298,"line":382},[296,839,303],{"class":302},[296,841,842],{"class":306}," tar",[296,844,845],{"class":306}," Cxzvf",[296,847,848],{"class":306}," \u002Fopt\u002Fcni\u002Fbin",[296,850,851],{"class":306}," cni-plugins-linux-",[296,853,816],{"class":433},[296,855,819],{"class":306},[296,857,810],{"class":433},[296,859,824],{"class":306},[15,861,862,865,866,869,870,873,874,877,878,881],{},[61,863,864],{},"\u002Fopt\u002Fcni\u002Fbin"," 是 nerdctl 預設尋找 CNI plugins 的位置。裡面會有 ",[61,867,868],{},"bridge","（建立橋接網卡）、",[61,871,872],{},"host-local","（分配 IP）、",[61,875,876],{},"portmap","（Port 對應）、",[61,879,880],{},"firewall"," 等執行檔，nerdctl 建立容器時會依序呼叫它們。",[10,883,885],{"id":884},"安裝-nerdctl","安裝 nerdctl",[15,887,888,889,894],{},"到 ",[640,890,893],{"href":891,"rel":892},"https:\u002F\u002Fgithub.com\u002Fcontainerd\u002Fnerdctl\u002Freleases",[644],"nerdctl Releases"," 下載。nerdctl 提供兩種版本：",[19,896,897,905],{},[22,898,899,904],{},[25,900,901],{},[61,902,903],{},"nerdctl-x.y.z-linux-amd64.tar.gz","：只有 nerdctl 本身，containerd、runc、CNI 要自己裝（也就是本篇的做法）",[22,906,907,912],{},[25,908,909],{},[61,910,911],{},"nerdctl-full-x.y.z-linux-amd64.tar.gz","：一次附帶 containerd、runc、CNI plugins、BuildKit 等所有相依元件，適合全新的主機一次裝好",[287,914,916],{"className":289,"code":915,"language":291,"meta":292,"style":292},"NERDCTL_VERSION=1.7.6\nARCH=$(dpkg --print-architecture)\n\nwget https:\u002F\u002Fgithub.com\u002Fcontainerd\u002Fnerdctl\u002Freleases\u002Fdownload\u002Fv${NERDCTL_VERSION}\u002Fnerdctl-${NERDCTL_VERSION}-linux-${ARCH}.tar.gz\nsudo tar Cxzvf \u002Fusr\u002Flocal\u002Fbin nerdctl-${NERDCTL_VERSION}-linux-${ARCH}.tar.gz nerdctl\n\nnerdctl version\n",[61,917,918,928,942,946,969,995,999],{"__ignoreMap":292},[296,919,920,923,925],{"class":298,"line":299},[296,921,922],{"class":433},"NERDCTL_VERSION",[296,924,659],{"class":440},[296,926,927],{"class":306},"1.7.6\n",[296,929,930,932,934,936,938,940],{"class":298,"line":313},[296,931,667],{"class":433},[296,933,659],{"class":440},[296,935,672],{"class":433},[296,937,404],{"class":302},[296,939,407],{"class":336},[296,941,679],{"class":433},[296,943,944],{"class":298,"line":329},[296,945,386],{"emptyLinePlaceholder":385},[296,947,948,950,953,956,959,961,964,966],{"class":298,"line":349},[296,949,688],{"class":302},[296,951,952],{"class":306}," https:\u002F\u002Fgithub.com\u002Fcontainerd\u002Fnerdctl\u002Freleases\u002Fdownload\u002Fv",[296,954,955],{"class":433},"${NERDCTL_VERSION}",[296,957,958],{"class":306},"\u002Fnerdctl-",[296,960,955],{"class":433},[296,962,963],{"class":306},"-linux-",[296,965,816],{"class":433},[296,967,968],{"class":306},".tar.gz\n",[296,970,971,973,975,977,980,983,985,987,989,992],{"class":298,"line":369},[296,972,303],{"class":302},[296,974,842],{"class":306},[296,976,845],{"class":306},[296,978,979],{"class":306}," \u002Fusr\u002Flocal\u002Fbin",[296,981,982],{"class":306}," nerdctl-",[296,984,955],{"class":433},[296,986,963],{"class":306},[296,988,816],{"class":433},[296,990,991],{"class":306},".tar.gz",[296,993,994],{"class":306}," nerdctl\n",[296,996,997],{"class":298,"line":382},[296,998,386],{"emptyLinePlaceholder":385},[296,1000,1001,1003],{"class":298,"line":389},[296,1002,44],{"class":302},[296,1004,1005],{"class":306}," version\n",[15,1007,1008,1011],{},[61,1009,1010],{},"nerdctl version"," 同時顯示 Client 與 Server（containerd）的版本，兩者都有出現代表 nerdctl 已經成功連上 containerd。",[275,1013,1014],{"id":1014},"驗證",[287,1016,1018],{"className":289,"code":1017,"language":291,"meta":292,"style":292},"sudo nerdctl run -d --name web -p 8080:80 nginx:alpine\nsudo nerdctl ps\ncurl http:\u002F\u002Flocalhost:8080\n",[61,1019,1020,1046,1055],{"__ignoreMap":292},[296,1021,1022,1024,1027,1030,1032,1035,1038,1040,1043],{"class":298,"line":299},[296,1023,303],{"class":302},[296,1025,1026],{"class":306}," nerdctl",[296,1028,1029],{"class":306}," run",[296,1031,343],{"class":336},[296,1033,1034],{"class":336}," --name",[296,1036,1037],{"class":306}," web",[296,1039,525],{"class":336},[296,1041,1042],{"class":306}," 8080:80",[296,1044,1045],{"class":306}," nginx:alpine\n",[296,1047,1048,1050,1052],{"class":298,"line":313},[296,1049,303],{"class":302},[296,1051,1026],{"class":306},[296,1053,1054],{"class":306}," ps\n",[296,1056,1057,1060],{"class":298,"line":329},[296,1058,1059],{"class":302},"curl",[296,1061,1062],{"class":306}," http:\u002F\u002Flocalhost:8080\n",[10,1064,1066],{"id":1065},"連線公司的-harbor","連線公司的 Harbor",[275,1068,1069],{"id":1069},"登入",[15,1071,1072],{},"和 Docker 一樣：",[287,1074,1076],{"className":289,"code":1075,"language":291,"meta":292,"style":292},"sudo nerdctl login harbor.example.com\nsudo nerdctl pull harbor.example.com\u002Frealty\u002Fhouse-api:1.3.0\n",[61,1077,1078,1090],{"__ignoreMap":292},[296,1079,1080,1082,1084,1087],{"class":298,"line":299},[296,1081,303],{"class":302},[296,1083,1026],{"class":306},[296,1085,1086],{"class":306}," login",[296,1088,1089],{"class":306}," harbor.example.com\n",[296,1091,1092,1094,1096,1099],{"class":298,"line":313},[296,1093,303],{"class":302},[296,1095,1026],{"class":306},[296,1097,1098],{"class":306}," pull",[296,1100,1101],{"class":306}," harbor.example.com\u002Frealty\u002Fhouse-api:1.3.0\n",[275,1103,1104],{"id":1104},"自簽憑證",[15,1106,1107,1108,1111,1112,1115],{},"公司內部的 Harbor 常用自簽憑證，拉取時會出現 ",[61,1109,1110],{},"x509: certificate signed by unknown authority","。nerdctl 會讀取 ",[61,1113,1114],{},"\u002Fetc\u002Fcontainerd\u002Fcerts.d\u002F"," 底下的設定，把公司的 CA 憑證放進對應的資料夾：",[287,1117,1119],{"className":289,"code":1118,"language":291,"meta":292,"style":292},"sudo mkdir -p \u002Fetc\u002Fcontainerd\u002Fcerts.d\u002Fharbor.example.com\nsudo cp company-ca.crt \u002Fetc\u002Fcontainerd\u002Fcerts.d\u002Fharbor.example.com\u002Fca.crt\n",[61,1120,1121,1132],{"__ignoreMap":292},[296,1122,1123,1125,1127,1129],{"class":298,"line":299},[296,1124,303],{"class":302},[296,1126,522],{"class":306},[296,1128,525],{"class":336},[296,1130,1131],{"class":306}," \u002Fetc\u002Fcontainerd\u002Fcerts.d\u002Fharbor.example.com\n",[296,1133,1134,1136,1139,1142],{"class":298,"line":313},[296,1135,303],{"class":302},[296,1137,1138],{"class":306}," cp",[296,1140,1141],{"class":306}," company-ca.crt",[296,1143,1144],{"class":306}," \u002Fetc\u002Fcontainerd\u002Fcerts.d\u002Fharbor.example.com\u002Fca.crt\n",[287,1146,1150],{"className":1147,"code":1148,"language":1149,"meta":292,"style":292},"language-toml shiki shiki-themes github-dark","# \u002Fetc\u002Fcontainerd\u002Fcerts.d\u002Fharbor.example.com\u002Fhosts.toml\nserver = \"https:\u002F\u002Fharbor.example.com\"\n\n[host.\"https:\u002F\u002Fharbor.example.com\"]\n  ca = \"\u002Fetc\u002Fcontainerd\u002Fcerts.d\u002Fharbor.example.com\u002Fca.crt\"\n","toml",[61,1151,1152,1157,1162,1166,1171],{"__ignoreMap":292},[296,1153,1154],{"class":298,"line":299},[296,1155,1156],{},"# \u002Fetc\u002Fcontainerd\u002Fcerts.d\u002Fharbor.example.com\u002Fhosts.toml\n",[296,1158,1159],{"class":298,"line":313},[296,1160,1161],{},"server = \"https:\u002F\u002Fharbor.example.com\"\n",[296,1163,1164],{"class":298,"line":329},[296,1165,386],{"emptyLinePlaceholder":385},[296,1167,1168],{"class":298,"line":349},[296,1169,1170],{},"[host.\"https:\u002F\u002Fharbor.example.com\"]\n",[296,1172,1173],{"class":298,"line":369},[296,1174,1175],{},"  ca = \"\u002Fetc\u002Fcontainerd\u002Fcerts.d\u002Fharbor.example.com\u002Fca.crt\"\n",[15,1177,1178,1179,1182],{},"測試環境如果只是暫時要略過驗證，可以加 ",[61,1180,1181],{},"--insecure-registry","，但正式環境不要這樣用。",[10,1184,1186],{"id":1185},"和-docker-不一樣的地方","和 Docker 不一樣的地方",[15,1188,1189],{},"nerdctl 雖然和 Docker CLI 相容，還是有幾個地方容易卡住：",[19,1191,1192,1222,1239,1248,1257],{},[22,1193,1194,1197,1198,1201,1202,1205,1206,1209,1210,1213,1214,1217,1218,1221],{},[25,1195,1196],{},"containerd 有 Namespace","：nerdctl 預設使用 ",[61,1199,1200],{},"default"," 這個 Namespace，而 Kubernetes 的 kubelet 使用 ",[61,1203,1204],{},"k8s.io","。在 K8s 節點上用 ",[61,1207,1208],{},"nerdctl pull"," 拉下來的映像檔，",[25,1211,1212],{},"kubelet 看不到","；要查看 K8s 建立的容器，也要加 ",[61,1215,1216],{},"--namespace k8s.io","（或 ",[61,1219,1220],{},"-n k8s.io","）",[22,1223,1224,1230,1231,1234,1235,1238],{},[25,1225,1226,1229],{},[61,1227,1228],{},"nerdctl build"," 需要 BuildKit","：nerdctl 本身不會建置映像檔，要另外安裝並啟動 ",[61,1232,1233],{},"buildkitd","（",[61,1236,1237],{},"nerdctl-full"," 版本有附）。這幾台主機只負責執行容器、建置交給 CI，所以沒有安裝",[22,1240,1241,478,1244,1247],{},[25,1242,1243],{},"沒有常駐程式也代表沒有自動重啟管理員",[61,1245,1246],{},"--restart=always"," 是由 nerdctl 搭配 containerd 的機制處理，主機重開機後要確認容器有自動起來",[22,1249,1250,1253,1254,1256],{},[25,1251,1252],{},"預設需要 root","：上面的指令都加了 ",[61,1255,303],{},"。nerdctl 也支援 Rootless 模式，但需要額外設定",[22,1258,1259,1262,1263,1266,1267,1270,1271,1273],{},[25,1260,1261],{},"網卡名稱不同","：Docker 的預設橋接網卡是 ",[61,1264,1265],{},"docker0","，nerdctl 是 ",[61,1268,1269],{},"nerdctl0","，網段也不一樣。防火牆規則、監控設定如果有寫死 ",[61,1272,1265],{}," 要一起改",[10,1275,1277],{"id":1276},"錯誤紀錄移除-docker-後外部連不進容器","錯誤紀錄：移除 Docker 後外部連不進容器",[275,1279,1280],{"id":1280},"症狀",[15,1282,1283,1284,1286],{},"主機原本裝過 Docker，移除後改用 containerd + nerdctl。",[61,1285,753],{}," 啟動容器後：",[19,1288,1289,1298],{},[22,1290,1291,1292,757,1295],{},"在主機上 ",[61,1293,1294],{},"curl localhost:8080",[25,1296,1297],{},"正常",[22,1299,1300,1301,1304,1305],{},"從外部其他機器連 ",[61,1302,1303],{},"http:\u002F\u002F主機IP:8080"," 卻",[25,1306,1307],{},"一直沒有回應，最後逾時",[15,1309,1310,1311,269],{},"相同的問題在 nerdctl 的 GitHub 也有人回報：",[640,1312,1315],{"href":1313,"rel":1314},"https:\u002F\u002Fgithub.com\u002Fcontainerd\u002Fnerdctl\u002Fdiscussions\u002F2142",[644],"containerd\u002Fnerdctl#2142",[275,1317,1318],{"id":1318},"原因",[15,1320,1321],{},[53,1322],{"alt":1323,"src":1324},"移除 Docker 後的 iptables 殘留示意圖：外部請求進入主機的 eth0，iptables nat 表的 PREROUTING 鏈中，Docker 留下的 DOCKER 鏈規則仍然存在並排在前面，指向已經不存在的 docker0 網段，封包被導到錯的地方而逾時；nerdctl 透過 CNI portmap 建立的 CNI-HOSTPORT-DNAT 規則排在後面，本應把 8080 轉到 nerdctl0 橋接網卡上的容器 10.4.0.2:80；從 localhost 連線走的是 OUTPUT 鏈，不受影響，所以本機正常、外部逾時；解法是刪除 Docker 殘留的 iptables 規則、鏈與 docker0 網卡","\u002Fimages\u002Farticles\u002Fcontainerd-iptables-leftover.svg",[15,1326,1327,1330,1331,1337,1338,1341,1342,1345,1346,244,1349,1352,1353,1355,1356,1359],{},[61,1328,1329],{},"apt remove docker-ce"," 只會移除程式，",[25,1332,1333,1334,1336],{},"Docker 在系統上建立的 iptables 規則與 ",[61,1335,1265],{}," 網卡不會一起清掉","。Docker 會在 ",[61,1339,1340],{},"nat"," 表裡建立自己的 ",[61,1343,1344],{},"DOCKER"," 鏈，並在 ",[61,1347,1348],{},"PREROUTING",[61,1350,1351],{},"OUTPUT"," 中插入規則指向它；nerdctl 透過 CNI 的 ",[61,1354,876],{}," 外掛建立的則是 ",[61,1357,1358],{},"CNI-HOSTPORT-DNAT"," 這組規則。",[15,1361,1362,1363,1365,1366,1369,1370,269],{},"外部連進來的封包會先經過 ",[61,1364,1348],{},"，Docker 殘留的規則仍然排在前面，干擾了原本應該由 CNI 處理的轉送；而從主機本身用 ",[61,1367,1368],{},"localhost"," 連線，走的是另一條路徑，所以本機測試一切正常。這也是這個問題很難發現的原因：",[25,1371,1372],{},"本機 curl 沒問題，只有從外面連才會出事",[275,1374,1375],{"id":1375},"解決辦法",[15,1377,1378],{},"清除 Docker 殘留的 iptables 規則與網卡。",[728,1380,1381],{},[15,1382,1383],{},"⚠️ 修改 iptables 前，先確認自己不會把 SSH 連線一起擋掉，並且最好在有主控台可以登入的情況下操作。",[15,1385,1386],{},[25,1387,1388],{},"1. 先備份目前的規則",[287,1390,1392],{"className":289,"code":1391,"language":291,"meta":292,"style":292},"sudo iptables-save > ~\u002Fiptables-backup-$(date +%Y%m%d).rules\n",[61,1393,1394],{"__ignoreMap":292},[296,1395,1396,1398,1401,1403,1406,1408,1411,1414,1417],{"class":298,"line":299},[296,1397,303],{"class":302},[296,1399,1400],{"class":306}," iptables-save",[296,1402,458],{"class":440},[296,1404,1405],{"class":306}," ~\u002Fiptables-backup-",[296,1407,672],{"class":433},[296,1409,1410],{"class":302},"date",[296,1412,1413],{"class":306}," +%Y%m%d",[296,1415,1416],{"class":433},")",[296,1418,1419],{"class":306},".rules\n",[15,1421,1422],{},[25,1423,1424],{},"2. 找出 Docker 相關的規則",[287,1426,1428],{"className":289,"code":1427,"language":291,"meta":292,"style":292},"# 列出 nat 表的規則與編號\nsudo iptables -t nat -L -n --line-numbers\n\n# 也可以直接篩選出和 Docker 有關的規則\nsudo iptables-save | grep -i docker\n",[61,1429,1430,1435,1457,1461,1466],{"__ignoreMap":292},[296,1431,1432],{"class":298,"line":299},[296,1433,1434],{"class":634},"# 列出 nat 表的規則與編號\n",[296,1436,1437,1439,1442,1445,1448,1451,1454],{"class":298,"line":313},[296,1438,303],{"class":302},[296,1440,1441],{"class":306}," iptables",[296,1443,1444],{"class":336}," -t",[296,1446,1447],{"class":306}," nat",[296,1449,1450],{"class":336}," -L",[296,1452,1453],{"class":336}," -n",[296,1455,1456],{"class":336}," --line-numbers\n",[296,1458,1459],{"class":298,"line":329},[296,1460,386],{"emptyLinePlaceholder":385},[296,1462,1463],{"class":298,"line":349},[296,1464,1465],{"class":634},"# 也可以直接篩選出和 Docker 有關的規則\n",[296,1467,1468,1470,1472,1474,1477,1480],{"class":298,"line":369},[296,1469,303],{"class":302},[296,1471,1400],{"class":306},[296,1473,441],{"class":440},[296,1475,1476],{"class":302}," grep",[296,1478,1479],{"class":336}," -i",[296,1481,1482],{"class":306}," docker\n",[15,1484,1485],{},[25,1486,1487],{},"3. 刪除規則",[15,1489,1490,1491,244,1493,244,1495,1498,1499,1501,1502,1504],{},"先刪除 ",[61,1492,1348],{},[61,1494,1351],{},[61,1496,1497],{},"POSTROUTING"," 中指向 ",[61,1500,1344],{}," 的規則（用上一步看到的編號），再清空並刪除 ",[61,1503,1344],{}," 鏈本身：",[287,1506,1508],{"className":289,"code":1507,"language":291,"meta":292,"style":292},"# 刪除指定編號的規則，例如 PREROUTING 的第 1 條（編號依實際情況）\nsudo iptables -t nat -D PREROUTING 1\n\n# 清空 DOCKER 鏈內的規則\nsudo iptables -t nat -F DOCKER\n\n# 沒有任何規則再引用它之後，才能刪除這條鏈\nsudo iptables -t nat -X DOCKER\n",[61,1509,1510,1515,1534,1538,1543,1559,1563,1568],{"__ignoreMap":292},[296,1511,1512],{"class":298,"line":299},[296,1513,1514],{"class":634},"# 刪除指定編號的規則，例如 PREROUTING 的第 1 條（編號依實際情況）\n",[296,1516,1517,1519,1521,1523,1525,1528,1531],{"class":298,"line":313},[296,1518,303],{"class":302},[296,1520,1441],{"class":306},[296,1522,1444],{"class":336},[296,1524,1447],{"class":306},[296,1526,1527],{"class":336}," -D",[296,1529,1530],{"class":306}," PREROUTING",[296,1532,1533],{"class":336}," 1\n",[296,1535,1536],{"class":298,"line":329},[296,1537,386],{"emptyLinePlaceholder":385},[296,1539,1540],{"class":298,"line":349},[296,1541,1542],{"class":634},"# 清空 DOCKER 鏈內的規則\n",[296,1544,1545,1547,1549,1551,1553,1556],{"class":298,"line":369},[296,1546,303],{"class":302},[296,1548,1441],{"class":306},[296,1550,1444],{"class":336},[296,1552,1447],{"class":306},[296,1554,1555],{"class":336}," -F",[296,1557,1558],{"class":306}," DOCKER\n",[296,1560,1561],{"class":298,"line":382},[296,1562,386],{"emptyLinePlaceholder":385},[296,1564,1565],{"class":298,"line":389},[296,1566,1567],{"class":634},"# 沒有任何規則再引用它之後，才能刪除這條鏈\n",[296,1569,1570,1572,1574,1576,1578,1581],{"class":298,"line":398},[296,1571,303],{"class":302},[296,1573,1441],{"class":306},[296,1575,1444],{"class":336},[296,1577,1447],{"class":306},[296,1579,1580],{"class":336}," -X",[296,1582,1558],{"class":306},[15,1584,1585,1586,1589,1590,1595,1596,1599,1600,244,1602,244,1605,1608],{},"刪除一條規則後，後面規則的編號會往前移，所以",[25,1587,1588],{},"每刪一條就重新列一次","，或是從編號大的開始刪，避免刪錯（參考 ",[640,1591,1594],{"href":1592,"rel":1593},"https:\u002F\u002Fbobcares.com\u002Fblog\u002Fiptables-index-of-deletion-too-big\u002F",[644],"iptables: Index of deletion too big","）。",[61,1597,1598],{},"filter"," 表中的 ",[61,1601,1344],{},[61,1603,1604],{},"DOCKER-USER",[61,1606,1607],{},"DOCKER-ISOLATION-STAGE-1\u002F2"," 等鏈也用同樣的方式處理。",[15,1610,1611],{},[25,1612,1613],{},"4. 刪除 docker0 網卡",[287,1615,1617],{"className":289,"code":1616,"language":291,"meta":292,"style":292},"ip link show                     # 找到 docker0\nsudo ip link set docker0 down\nsudo ip link delete docker0\n",[61,1618,1619,1633,1651],{"__ignoreMap":292},[296,1620,1621,1624,1627,1630],{"class":298,"line":299},[296,1622,1623],{"class":302},"ip",[296,1625,1626],{"class":306}," link",[296,1628,1629],{"class":306}," show",[296,1631,1632],{"class":634},"                     # 找到 docker0\n",[296,1634,1635,1637,1640,1642,1645,1648],{"class":298,"line":313},[296,1636,303],{"class":302},[296,1638,1639],{"class":306}," ip",[296,1641,1626],{"class":306},[296,1643,1644],{"class":306}," set",[296,1646,1647],{"class":306}," docker0",[296,1649,1650],{"class":306}," down\n",[296,1652,1653,1655,1657,1659,1662],{"class":298,"line":329},[296,1654,303],{"class":302},[296,1656,1639],{"class":306},[296,1658,1626],{"class":306},[296,1660,1661],{"class":306}," delete",[296,1663,1664],{"class":306}," docker0\n",[15,1666,1667,1668,1671,1672,1675,1676,1678,1679,1684],{},"（舊的做法是 ",[61,1669,1670],{},"ifconfig docker0 down","，但 ",[61,1673,1674],{},"ifconfig"," 在新版的 Ubuntu 已經不是預設安裝，建議改用 ",[61,1677,1623],{}," 指令；參考 ",[640,1680,1683],{"href":1681,"rel":1682},"https:\u002F\u002Fstackoverflow.com\u002Fquestions\u002F34326704\u002Fhow-do-i-delete-virtual-interface-in-linux",[644],"How do I delete virtual interface in Linux","。）",[15,1686,1687],{},[25,1688,1689],{},"5. 重新建立容器並從外部驗證",[287,1691,1693],{"className":289,"code":1692,"language":291,"meta":292,"style":292},"sudo nerdctl rm -f web\nsudo nerdctl run -d --name web -p 8080:80 nginx:alpine\n\n# 確認 CNI 的 Port 對應規則存在\nsudo iptables -t nat -L CNI-HOSTPORT-DNAT -n\n\n# 從另一台機器測試\ncurl http:\u002F\u002F\u003C主機IP>:8080\n",[61,1694,1695,1710,1730,1734,1739,1757,1761,1766],{"__ignoreMap":292},[296,1696,1697,1699,1701,1704,1707],{"class":298,"line":299},[296,1698,303],{"class":302},[296,1700,1026],{"class":306},[296,1702,1703],{"class":306}," rm",[296,1705,1706],{"class":336}," -f",[296,1708,1709],{"class":306}," web\n",[296,1711,1712,1714,1716,1718,1720,1722,1724,1726,1728],{"class":298,"line":313},[296,1713,303],{"class":302},[296,1715,1026],{"class":306},[296,1717,1029],{"class":306},[296,1719,343],{"class":336},[296,1721,1034],{"class":336},[296,1723,1037],{"class":306},[296,1725,525],{"class":336},[296,1727,1042],{"class":306},[296,1729,1045],{"class":306},[296,1731,1732],{"class":298,"line":329},[296,1733,386],{"emptyLinePlaceholder":385},[296,1735,1736],{"class":298,"line":349},[296,1737,1738],{"class":634},"# 確認 CNI 的 Port 對應規則存在\n",[296,1740,1741,1743,1745,1747,1749,1751,1754],{"class":298,"line":369},[296,1742,303],{"class":302},[296,1744,1441],{"class":306},[296,1746,1444],{"class":336},[296,1748,1447],{"class":306},[296,1750,1450],{"class":336},[296,1752,1753],{"class":306}," CNI-HOSTPORT-DNAT",[296,1755,1756],{"class":336}," -n\n",[296,1758,1759],{"class":298,"line":382},[296,1760,386],{"emptyLinePlaceholder":385},[296,1762,1763],{"class":298,"line":389},[296,1764,1765],{"class":634},"# 從另一台機器測試\n",[296,1767,1768,1770,1773,1776,1779,1782,1785],{"class":298,"line":398},[296,1769,1059],{"class":302},[296,1771,1772],{"class":306}," http:\u002F\u002F",[296,1774,1775],{"class":440},"\u003C",[296,1777,1778],{"class":306},"主機I",[296,1780,1781],{"class":433},"P",[296,1783,1784],{"class":440},">",[296,1786,1787],{"class":306},":8080\n",[15,1789,1790,1791,1794,1795,1798],{},"如果主機有用 ",[61,1792,1793],{},"iptables-persistent"," 之類的工具把規則存起來，開機時會自動載回來，記得清理後重新儲存（",[61,1796,1797],{},"sudo netfilter-persistent save","），不然重開機問題又回來了。",[275,1800,1801],{"id":1801},"避免再發生",[19,1803,1804,1810,1816],{},[22,1805,1806,1809],{},[25,1807,1808],{},"新主機直接裝 containerd + nerdctl","，不要先裝 Docker 再移除",[22,1811,1812,1813,1815],{},"舊主機要換掉 Docker 時，把「清理 iptables 與 ",[61,1814,1265],{},"」寫進移轉步驟，而不是等出問題才處理",[22,1817,1818,1819,1822,1823],{},"驗收時",[25,1820,1821],{},"一定要從外部機器測試","，不能只在主機上 ",[61,1824,1825],{},"curl localhost",[10,1827,1828],{"id":1828},"參考資料",[19,1830,1831,1838,1845],{},[22,1832,1833],{},[640,1834,1837],{"href":1835,"rel":1836},"https:\u002F\u002Fgithub.com\u002Fcontainerd\u002Fcontainerd\u002Fblob\u002Fmain\u002Fdocs\u002Fgetting-started.md",[644],"containerd Getting Started",[22,1839,1840],{},[640,1841,1844],{"href":1842,"rel":1843},"https:\u002F\u002Fdocs.docker.com\u002Fengine\u002Finstall\u002Fubuntu\u002F",[644],"Install Docker Engine on Ubuntu（containerd.io 套件來源）",[22,1846,1847],{},[640,1848,1851],{"href":1849,"rel":1850},"https:\u002F\u002Fwww.qikqiak.com\u002Fk8strain2\u002Fcontainerd\u002Fnerdctl\u002F",[644],"nerdctl 安裝說明",[10,1853,1854],{"id":1854},"一句話總結",[15,1856,1857,1858,1860],{},"Docker 底層本來就是 containerd，拿掉 dockerd 之後，只要自己補上建立容器的 runc 與負責網路的 CNI plugins，再用和 Docker 指令相容的 nerdctl 操作，就能用更少的元件跑一樣的容器；但從 Docker 換過來的主機，記得清掉 Docker 殘留的 iptables 規則與 ",[61,1859,1265],{},"，而且驗收時一定要從外部連線測試。",[1862,1863,1864],"style",{},"html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":292,"searchDepth":313,"depth":313,"links":1866},[1867,1868,1869,1870,1875,1876,1877,1880,1884,1885,1891,1892],{"id":12,"depth":313,"text":13},{"id":48,"depth":313,"text":49},{"id":178,"depth":313,"text":179},{"id":272,"depth":313,"text":273,"children":1871},[1872,1873,1874],{"id":277,"depth":329,"text":278},{"id":464,"depth":329,"text":273},{"id":505,"depth":329,"text":505},{"id":595,"depth":313,"text":596},{"id":746,"depth":313,"text":747},{"id":884,"depth":313,"text":885,"children":1878},[1879],{"id":1014,"depth":329,"text":1014},{"id":1065,"depth":313,"text":1066,"children":1881},[1882,1883],{"id":1069,"depth":329,"text":1069},{"id":1104,"depth":329,"text":1104},{"id":1185,"depth":313,"text":1186},{"id":1276,"depth":313,"text":1277,"children":1886},[1887,1888,1889,1890],{"id":1280,"depth":329,"text":1280},{"id":1318,"depth":329,"text":1318},{"id":1375,"depth":329,"text":1375},{"id":1801,"depth":329,"text":1801},{"id":1828,"depth":313,"text":1828},{"id":1854,"depth":313,"text":1854},"2024-06-18",null,"md",{},"\u002Farticles\u002Fcontainerd-and-nerdctl",{"title":5,"description":292},"articles\u002Fcontainerd-and-nerdctl",[40,44,1901,1902,1903],"容器","Linux","DevOps","KaKC42KosE0tE9tml1JzT3OhkEa9Q15MO3Em9smbTVE",1792959150380]