5 min read

安裝 nerdctl

Github

使用 k3s / k8s 內建使用ctr ,雖然可以透過Docker build 創建容器,但無法使用 需要另外匯出類似這樣,但最後建構完再匯出到ctr 時間太久。

此時可以考慮使用nerdctl,文末提供一鍵安裝腳本會自動偵測cpu架構下載相對應檔案。

#!/bin/bash
set -e
set -o pipefail

DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
$CONTAINER_IMAGE=test

docker build -t $CONTAINER_IMAGE
docker save $CONTAINER_IMAGE -o $DIR/test.tar
k3s ctr images import $DIR/test.tar

而nerdctl 在Github 分為兩個版本 精簡/全量主要差異在於如果要建構容器時,建議使用full 版本支持度會更高 ,不用再去安裝其他擴展。

一鍵安裝shell指令

#!/bin/bash

# nerdctl-full 自動安裝腳本
# 自動檢測系統架構並下載對應版本

set -e

# 顏色定義
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 日誌函數
log_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

log_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

log_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# 檢測系統架構
detect_arch() {
    local arch=$(uname -m)
    case $arch in
        x86_64)
            echo "amd64"
            ;;
        aarch64|arm64)
            echo "arm64"
            ;;
        armv7l)
            echo "arm-v7"
            ;;
        *)
            log_error "不支持的架構: $arch"
            exit 1
            ;;
    esac
}

# 檢測操作系統
detect_os() {
    local os=$(uname -s | tr '[:upper:]' '[:lower:]')
    case $os in
        linux)
            echo "linux"
            ;;
        darwin)
            log_error "macOS 不支持 nerdctl-full,請使用 brew 或其他方式安裝"
            exit 1
            ;;
        *)
            log_error "不支持的操作系統: $os"
            exit 1
            ;;
    esac
}

# 獲取最新版本號
get_latest_version() {
    log_info "獲取最新版本信息..."
    local version=$(curl -s https://api.github.com/repos/containerd/nerdctl/releases/latest | grep '"tag_name"' | cut -d'"' -f4)
    if [ -z "$version" ]; then
        log_error "無法獲取最新版本信息"
        exit 1
    fi
    echo $version
}

# 下載文件
download_file() {
    local url=$1
    local filename=$2
    
    log_info "下載 $filename..."
    
    # 檢查是否有 wget 或 curl
    if command -v wget >/dev/null 2>&1; then
        wget -O "$filename" "$url"
    elif command -v curl >/dev/null 2>&1; then
        curl -L -o "$filename" "$url"
    else
        log_error "需要 wget 或 curl 來下載文件"
        exit 1
    fi
}

# 驗證下載的文件
verify_download() {
    local filename=$1
    
    if [ ! -f "$filename" ]; then
        log_error "下載失敗: $filename 不存在"
        exit 1
    fi
    
    local size=$(stat -c%s "$filename" 2>/dev/null || stat -f%z "$filename" 2>/dev/null)
    if [ "$size" -lt 1000000 ]; then  # 小於 1MB 可能是錯誤文件
        log_error "下載的文件可能有問題,大小只有 $size bytes"
        exit 1
    fi
    
    log_success "文件下載完成,大小: $size bytes"
}

# 安裝 nerdctl-full
install_nerdctl() {
    local filename=$1
    local install_path=${2:-/usr/local}
    
    log_info "解壓並安裝到 $install_path..."
    
    # 檢查是否需要 sudo
    if [ ! -w "$install_path" ]; then
        local sudo_cmd="sudo"
        log_warning "需要 sudo 權限安裝到 $install_path"
    else
        local sudo_cmd=""
    fi
    
    # 解壓安裝
    $sudo_cmd tar Cxzvf "$install_path" "$filename"
    
    # 驗證安裝
    if [ -f "$install_path/bin/nerdctl" ]; then
        log_success "nerdctl 安裝成功!"
        log_info "版本信息:"
        "$install_path/bin/nerdctl" version || true
    else
        log_error "安裝驗證失敗"
        exit 1
    fi
}

# 設置 systemd 服務(可選)
setup_services() {
    local install_path=${1:-/usr/local}
    
    read -p "是否要啟動 containerd 和 buildkit 服務? (y/n): " -n 1 -r
    echo
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        log_info "啟動服務..."
        
        if command -v systemctl >/dev/null 2>&1; then
            sudo systemctl daemon-reload
            sudo systemctl enable containerd || log_warning "無法啟用 containerd 服務"
            sudo systemctl start containerd || log_warning "無法啟動 containerd 服務"
            sudo systemctl enable buildkit || log_warning "無法啟用 buildkit 服務"
            sudo systemctl start buildkit || log_warning "無法啟動 buildkit 服務"
            
            log_success "服務設置完成"
        else
            log_warning "systemctl 不可用,請手動啟動服務"
        fi
    fi
}

# 主函數
main() {
    log_info "nerdctl-full 自動安裝腳本"
    log_info "=============================="
    
    # 檢測系統信息
    local os=$(detect_os)
    local arch=$(detect_arch)
    local version=${1:-$(get_latest_version)}
    local install_path=${2:-/usr/local}
    
    log_info "檢測到的系統信息:"
    log_info "  操作系統: $os"
    log_info "  架構: $arch"
    log_info "  版本: $version"
    log_info "  安裝路徑: $install_path"
    
    # 構造下載 URL 和文件名
    local filename="nerdctl-full-${version}-${os}-${arch}.tar.gz"
    local download_url="https://github.com/containerd/nerdctl/releases/download/${version}/${filename}"
    
    log_info "下載 URL: $download_url"
    
    # 確認下載
    read -p "是否繼續下載並安裝? (y/n): " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        log_info "安裝已取消"
        exit 0
    fi
    
    # 清理舊文件
    [ -f "$filename" ] && rm -f "$filename"
    
    # 下載文件
    download_file "$download_url" "$filename"
    
    # 驗證下載
    verify_download "$filename"
    
    # 安裝
    install_nerdctl "$filename" "$install_path"
    
    # 設置服務
    setup_services "$install_path"
    
    # 清理下載文件
    read -p "是否刪除下載的安裝包? (y/n): " -n 1 -r
    echo
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        rm -f "$filename"
        log_info "安裝包已刪除"
    fi
    
    # 完成信息
    log_success "==============================================="
    log_success "nerdctl-full 安裝完成!"
    log_success "==============================================="
    log_info "使用方法:"
    log_info "  sudo $install_path/bin/nerdctl version"
    log_info "  sudo $install_path/bin/nerdctl run hello-world"
    log_info ""
    log_info "如果要使用 rootless 模式:"
    log_info "  $install_path/bin/containerd-rootless-setuptool.sh install"
    log_info ""
    log_info "更多信息請查看: https://github.com/containerd/nerdctl"
}

# 顯示幫助信息
show_help() {
    echo "用法: $0 [版本] [安裝路徑]"
    echo ""
    echo "參數:"
    echo "  版本      指定要安裝的版本 (默認: 最新版本)"
    echo "  安裝路徑   指定安裝目錄 (默認: /usr/local)"
    echo ""
    echo "示例:"
    echo "  $0                    # 安裝最新版本到 /usr/local"
    echo "  $0 v2.1.3            # 安裝指定版本"
    echo "  $0 v2.1.3 /opt       # 安裝到指定目錄"
    echo ""
    echo "支持的架構: amd64, arm64, arm-v7"
    echo "支持的系統: Linux"
}

# 檢查參數
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
    show_help
    exit 0
fi

# 運行主函數
main "$@"