diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index bcdad38..a2afa74 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -16,33 +16,32 @@ concurrency: env: BUILDKIT_PROGRESS: "plain" # Full logs for CI build. - REGISTRY_SRC: ${{ vars.REGISTRY_SRC || 'docker.io' }} # For BASE_NAMESPACE of images: where to pull base images from, docker.io or other source registry URL. - REGISTRY_DST: ${{ vars.REGISTRY_DST || 'docker.io' }} # For tags of built images: where to push images to, docker.io or other destination registry URL. + REGISTRY_SRC: ${{ vars.REGISTRY_SRC || 'quay.io' }} # For BASE_NAMESPACE of images: where to pull base images from, docker.io or other source registry URL. + REGISTRY_DST: ${{ vars.REGISTRY_DST || 'quay.io' }} # For tags of built images: where to push images to, docker.io or other destination registry URL. # DOCKER_REGISTRY_USERNAME and DOCKER_REGISTRY_PASSWORD is required for docker image push, they should be set in CI secrets. DOCKER_REGISTRY_USERNAME: ${{ vars.DOCKER_REGISTRY_USERNAME }} DOCKER_REGISTRY_PASSWORD: ${{ secrets.DOCKER_REGISTRY_PASSWORD }} # used to sync image to mirror registry DOCKER_MIRROR_REGISTRY_USERNAME: ${{ vars.DOCKER_MIRROR_REGISTRY_USERNAME }} DOCKER_MIRROR_REGISTRY_PASSWORD: ${{ secrets.DOCKER_MIRROR_REGISTRY_PASSWORD }} + CI_PROJECT_NAME: ${{ vars.CI_PROJECT_NAME || 'LabNow/lab-container' }} jobs: job-k3s-ctk: name: 'k3s-ctk' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: | - source ./tool.sh - build_image k3s-ctk latest docker_k8s/k3s-ctk.Dockerfile && push_image + source ./tool.sh && build_image k3s-ctk latest docker_kube/k3s-ctk.Dockerfile && push_image job-k0s-ctk: name: 'k0s-ctk' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - run: | - source ./tool.sh - build_image k0s-ctk latest docker_k8s/k0s-ctk.Dockerfile && push_image + source ./tool.sh && build_image k0s-ctk latest docker_kube/k0s-ctk.Dockerfile && push_image ## Sync all images in this build (listed by "names") to mirror registry. @@ -50,12 +49,13 @@ jobs: needs: ["job-k3s-ctk", "job-k0s-ctk"] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - env: AUTH_FILE_CONTENT: ${{ secrets.AUTH_FILE_CONTENT }} + DOCKER_MIRROR_REGISTRY: ${{ vars.DOCKER_MIRROR_REGISTRY }} run: | - source ./tool.sh && ls -alh ./ + source ./tool.sh printf '%s' "$AUTH_FILE_CONTENT" > .github/workflows/auth.json && ls -alh ./.github/workflows printenv | grep -v 'PATH' > /tmp/docker.env && echo "REGISTRY_URL=${REGISTRY_DST}" >> /tmp/docker.env - docker run --rm --env-file /tmp/docker.env -v $(pwd):/tmp -w /tmp qpod/docker-kit \ - image-syncer --proc=8 --retries=2 --images /tmp/task_sync_imgs/images.yaml --auth /tmp/.github/workflows/auth.json + docker run --rm --env-file /tmp/docker.env -v $(pwd):/tmp -w /tmp ${IMG_PREFIX_DST:-labnow}/docker-kit \ + python /opt/utils/image-syncer/run_jobs.py --auth-file=/tmp/.github/workflows/auth.json diff --git a/docker_k8s/README.md b/docker_k8s/README.md deleted file mode 100644 index 0cc8694..0000000 --- a/docker_k8s/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# k8s reload images - -## k3s - -```bash -docker run --rm -it -v /opt/k3s/:/tmp/ quay.io/labnow/k3s-ctk - -cd /opt/k3s - -zstd -cd ./k3s-airgap-images-${ARCH:-amd64}.tar.zst | docker load - -source ./script-setup-k3s.sh && create_cri_dockerd_unit_files - -INSTALL_K3S_SKIP_DOWNLOAD=true INSTALL_K3S_BIN_DIR=/opt/k3s ./script-get-k3s-io.sh --docker -data-dir /data/storage/data-k3s - -sudo ln -sf /opt/k3s/k3s* /opt/k3s/kubectl /opt/k3s/cri-docker /usr/local/bin/ -``` diff --git a/docker_kube/README.md b/docker_kube/README.md new file mode 100644 index 0000000..ee321f6 --- /dev/null +++ b/docker_kube/README.md @@ -0,0 +1,108 @@ +# LabNow Container Kit (Kubernetes Air-gap Installation) + +This project provides one-click installation assets for deploying Kubernetes (`k3s` / `k0s`) in air-gapped (offline) environments. + +All binaries, offline image bundles, and setup scripts are packaged into lightweight Docker images. Users can pull these images on a connected machine, transfer them to the offline host, and extract the assets using a volume mount to complete the installation without internet access. + +## Workflow + +1. **Build (Online)**: The Dockerfile downloads Kubernetes binaries, `kubectl`, `helm`, and the air-gap image bundle, packaging them into a runner image. +2. **Deploy (Offline)**: + - Export/pull the built image on the target host. + - Run the container with a volume mount to copy installation assets to the host filesystem. + - Run the provided scripts to install the cluster. + +--- + +## Image Components + +The tools and files included in each container image: + +| Component Role | `k3s-ctk` Image | `k0s-ctk` Image | Description | +| :--- | :--- | :--- | :--- | +| **Kubernetes Engine** | `k3s` | `k0s` | The core Kubernetes distribution binary. | +| **Air-gap Image Bundle** | `k3s-airgap-images-*.tar.zst` | `k0s-airgap-bundle-*` | System container images bundle for offline deployment. | +| **Kubernetes CLI** | `kubectl` | `kubectl` | Command-line tool for control plane operations. | +| **Package Manager** | `helm` | `helm` | Tool for managing Kubernetes pre-packaged charts. | +| **CRI Adapter** | `cri-dockerd` | *N/A* | Adapter to use Docker as the container runtime (embedded in K0s). | +| **Official Installer** | `script-get-k3s-io.sh` | *N/A* | Official installation script (embedded in K0s). | +| **Setup Helper Script** | `script-setup-k3s.sh` | `script-setup-k0s.sh` | Scripts containing functions for configuration and setup. | + +--- + +## Air-Gap Installation + +### Option A: Install K3s (with Docker Runtime) + +#### 1. Extract installation assets +Run the image to copy all assets to `/opt/k3s` on the host: +```bash +docker run --rm -it -v /opt/k3s:/tmp quay.io/labnow/k3s-ctk:latest +``` + +#### 2. Load K3s air-gap images +Import the K3s system images into your Docker daemon: +```bash +cd /opt/k3s +zstd -cd ./k3s-airgap-images-${ARCH:-amd64}.tar.zst | docker load +``` + +#### 3. Configure and start cri-dockerd +```bash +# Generate systemd socket and service unit files +source ./script-setup-k3s.sh && create_cri_dockerd_unit_files + +# Enable and start the service +sudo systemctl daemon-reload +sudo systemctl enable --now cri-docker.socket cri-docker.service +``` + +#### 4. Run the offline installer +```bash +INSTALL_K3S_SKIP_DOWNLOAD=true \ +INSTALL_K3S_BIN_DIR=/opt/k3s \ +./script-get-k3s-io.sh --docker --data-dir /data/storage/data-k3s +``` + +#### 5. Link binaries to PATH (Optional) +```bash +sudo ln -sf /opt/k3s/k3s* /opt/k3s/kubectl /opt/k3s/cri-dockerd /usr/local/bin/ +``` + +--- + +### Option B: Install K0s + +#### 1. Extract installation assets +Run the image to copy all assets to `/opt/k0s` on the host: +```bash +docker run --rm -it -v /opt/k0s:/tmp quay.io/labnow/k0s-ctk:latest +``` + +#### 2. Copy binaries and setup the air-gap bundle +K0s loads offline images from `/var/lib/k0s/images/` by default. +```bash +cd /opt/k0s + +# Copy binaries to PATH +sudo cp ./k0s ./kubectl ./helm /usr/local/bin/ + +# Copy the air-gap bundle to the designated directory +sudo mkdir -p /var/lib/k0s/images/ +sudo cp ./k0s-airgap-bundle-* /var/lib/k0s/images/ +``` + +#### 3. Install and start K0s service +```bash +# Install as a single-node controller + worker +sudo k0s install controller --single --enable-worker + +# Start the service +sudo k0s start +``` + +#### 4. Verify installation +```bash +sudo k0s status +sudo k0s kubectl get nodes +``` diff --git a/docker_k8s/k0s-ctk.Dockerfile b/docker_kube/k0s-ctk.Dockerfile similarity index 63% rename from docker_k8s/k0s-ctk.Dockerfile rename to docker_kube/k0s-ctk.Dockerfile index 9d0e409..6aa8b93 100644 --- a/docker_k8s/k0s-ctk.Dockerfile +++ b/docker_kube/k0s-ctk.Dockerfile @@ -9,11 +9,12 @@ LABEL maintainer="haobibo@gmail.com" COPY work /opt/utils/ RUN set -eux && chmod +x /opt/utils/*.sh \ - && source /opt/utils/script-setup-k8s-common.sh && setup_verify_arch && setup_kubectl && setup_helm \ - && source /opt/utils/script-setup-k0s.sh && setup_k0s && setup_k0s_pack \ + && source /opt/utils/script-setup-k8s-common.sh && setup_verify_arch && setup_kubectl && setup_helm && setup_k9s \ + && source /opt/utils/script-setup-k0s.sh && setup_k0s && setup_k0s_pack \ + && mv /opt/k8s/* /opt/k0s/ \ && mv /opt/utils/script-setup-k0s.sh /opt/k0s/ \ - && mv /opt/k8s/* /opt/k0s/ && rm -rf /opt/k8s \ - && ls -alh /opt/* + + && rm -rf /opt/k8s && ls -alh /opt/* FROM docker.io/busybox diff --git a/docker_k8s/k3s-ctk.Dockerfile b/docker_kube/k3s-ctk.Dockerfile similarity index 51% rename from docker_k8s/k3s-ctk.Dockerfile rename to docker_kube/k3s-ctk.Dockerfile index 1ca5081..e86568e 100644 --- a/docker_k8s/k3s-ctk.Dockerfile +++ b/docker_kube/k3s-ctk.Dockerfile @@ -9,12 +9,11 @@ LABEL maintainer="haobibo@gmail.com" COPY work /opt/utils/ RUN set -eux && chmod +x /opt/utils/*.sh \ - && source /opt/utils/script-setup-k8s-common.sh && setup_verify_arch && setup_kubectl && setup_helm \ - && source /opt/utils/script-setup-k3s.sh && setup_k3s && setup_cri_dockerd && setup_k3s_pack \ - && mv /opt/utils/script-setup-k3s.sh /opt/k3s/ \ - && mv /opt/utils/script-get-k3s-io.sh /opt/k3s/ \ - && mv /opt/k8s/* /opt/k3s/ && rm -rf /opt/k8s \ - && ls -alh /opt/* + && source /opt/utils/script-setup-k8s-common.sh && setup_verify_arch && setup_kubectl && setup_helm && setup_k9s \ + && source /opt/utils/script-setup-k3s.sh && setup_k3s && setup_cri_dockerd && setup_k3s_pack \ + && mv /opt/k8s/* /opt/k3s/ \ + && mv /opt/utils/script-setup-k3s.sh /opt/utils/script-get-k3s-io.sh /opt/k3s/ \ + && rm -rf /opt/k8s && ls -alh /opt/* FROM docker.io/busybox diff --git a/docker_k8s/work/script-get-k3s-io.sh b/docker_kube/work/script-get-k3s-io.sh similarity index 100% rename from docker_k8s/work/script-get-k3s-io.sh rename to docker_kube/work/script-get-k3s-io.sh diff --git a/docker_k8s/work/script-setup-k0s.sh b/docker_kube/work/script-setup-k0s.sh similarity index 100% rename from docker_k8s/work/script-setup-k0s.sh rename to docker_kube/work/script-setup-k0s.sh diff --git a/docker_k8s/work/script-setup-k3d.sh b/docker_kube/work/script-setup-k3d.sh similarity index 100% rename from docker_k8s/work/script-setup-k3d.sh rename to docker_kube/work/script-setup-k3d.sh diff --git a/docker_k8s/work/script-setup-k3s.sh b/docker_kube/work/script-setup-k3s.sh similarity index 100% rename from docker_k8s/work/script-setup-k3s.sh rename to docker_kube/work/script-setup-k3s.sh diff --git a/docker_k8s/work/script-setup-k8s-common.sh b/docker_kube/work/script-setup-k8s-common.sh similarity index 68% rename from docker_k8s/work/script-setup-k8s-common.sh rename to docker_kube/work/script-setup-k8s-common.sh index 936d856..c7ebe55 100644 --- a/docker_k8s/work/script-setup-k8s-common.sh +++ b/docker_kube/work/script-setup-k8s-common.sh @@ -31,3 +31,18 @@ setup_helm() { && chmod +x /opt/k8s/helm /opt/k8s/helm version } + +setup_k9s() { + # ref: https://github.com/derailed/k9s , the binary is roughly 120MB + local K9S_ARCH=$ARCH + [ "$K9S_ARCH" = "arm" ] && K9S_ARCH="armv7" + + VER_K9S=$(curl -sL https://github.com/derailed/k9s/releases.atom | grep 'releases/tag/v' | grep -v 'rc' | head -1 | sed -E 's/.*\/tag\/([^"]+).*/\1/') \ + && URL_K9S="https://github.com/derailed/k9s/releases/download/${VER_K9S}/k9s_Linux_${K9S_ARCH}.tar.gz" \ + && echo "Downloading K9s version ${VER_K9S} from: ${URL_K9S}" \ + && curl -L -s -o /tmp/k9s.tar.gz "${URL_K9S}" \ + && mkdir -pv /opt/k8s \ + && tar -zxvf /tmp/k9s.tar.gz -C /opt/k8s/ k9s \ + && chmod +x /opt/k8s/k9s + /opt/k8s/k9s version +}