1. Overview and Purpose
The objective is to construct a CI/CD pipeline integrating GitHub Actions with a local Kubernetes environment to automate the transition from source code push to deployment. This workflow eliminates manual intervention and executes automated rolling updates.
Target Workflow:
Git Push: Developer pushes code to the master branch.
Docker Build: GitHub Actions triggers the container image build.
Docker Push: The built image is pushed to a registry such as DockerHub.
Kubernetes Update: The cluster pulls the new image and executes a rolling update.
2. Establishing Kubernetes Connection and Authentication Settings
Defining appropriate authentication credentials (kubeconfig) is essential to allow GitHub Actions to operate the cluster from external environments.
2.1 Kubeconfig Extraction
Verify the current connection information in the local environment and extract the necessary data.
kubectl config view
The YAML structure includes the cluster server URL, certificate data, and user context. Registering this in GitHub Secrets requires caution to avoid PEM block parsing errors caused by line break codes or indentation issues.
2.2 Data Protection via Base64 Encoding
To maintain the integrity of certificate data, the kubeconfig file is encoded in Base64 before registration in GitHub Secrets.
# Execution example in Windows PowerShell environment
[Convert]::ToBase64String([IO.File]::ReadAllBytes("C:\Users\Administrator\.kube\config"))
The resulting string is stored in the GitHub repository under Settings > Secrets and variables > Actions as KUBE_CONFIG. Base64 encoding prevents binary data corruption in CI environments.
3. Workflow Definition and Troubleshooting
3.1 Initial Workflow Configuration (.github/workflows/docker-build.yml)
The initial definition ensures consistent execution of image building, pushing, and deployment.
name: Build and Deploy
on:
push:
branches:
- master
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Docker Login
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build Docker Image
run: |
docker build -t ${{ secrets.DOCKER_USERNAME }}/my-tomcat:latest .
- name: Push Docker Image
run: |
docker push ${{ secrets.DOCKER_USERNAME }}/my-tomcat:latest
- name: Set kube config
run: |
mkdir -p ~/.kube
echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > ~/.kube/config
- name: Deploy to Kubernetes
run: |
kubectl rollout restart deployment tomcat-deployment
3.2 Resolving PEM Parsing Errors
If the error “unable to load root certificates: unable to parse bytes as PEM block” occurs, the decoded file format from Secrets is likely invalid. Applying Base64 encoding and restoring it via base64 -d within the workflow reliably avoids this issue.
4. Introduction of Self-Hosted Runners
4.1 Network Boundary Issues
GitHub-hosted runners (ubuntu-latest) fail to resolve the name for Docker Desktop on local environments (kubernetes.docker.internal), resulting in connection errors.
Unable to connect to the server: dial tcp: lookup kubernetes.docker.internal: no such host
A Self-Hosted Runner operating within the local network enables direct access to internal resources.
4.2 Installation Steps for Windows
Select New self-hosted runner from Settings > Actions > Runners. Specify Windows as the OS and execute the PowerShell script to configure the runner.
# Runner placement and configuration
mkdir actions-runner; cd actions-runner
# (Execute configuration using the token provided by GitHub)
.\config.cmd --url https://github.com/[USER]/[REPO] --token [TOKEN]
.\run.cmd
4.3 Modifying the Workflow
Change the runner specification to self-hosted to enable job execution in the local environment.
runs-on: self-hosted
5. Command Compatibility in Cross-Platform Environments
Standard Linux commands like mkdir -p may fail on Windows runners. Adjusting steps to match PowerShell syntax eliminates environment-dependent errors.
- name: Set kube config
shell: powershell
run: |
if (!(Test-Path "$HOME\.kube")) {
New-Item -ItemType Directory -Path "$HOME\.kube"
}
[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("${{ secrets.KUBE_CONFIG }}")) | Out-File "$HOME\.kube\config"
6. Analysis of ErrImagePull and Manifest Adjustments
If a Pod enters the ErrImagePull state, verify the registry push status and the pull policy. If imagePullPolicy: Always is set, the system attempts to retrieve the image from the external registry even if it exists locally.
To prioritize locally cached images in a development environment, modify the Deployment manifest.
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat2-deployment
spec:
template:
spec:
containers:
- name: tomcat
image: abungard/my-tomcat:latest
imagePullPolicy: IfNotPresent
7. Conclusion and Future Outlook
Protecting certificate data with Base64 is an effective method for preventing authentication errors in CI environments. Self-Hosted Runners are indispensable for ensuring network reachability when deploying to local environments. Future improvements include transitioning from latest tags to Git SHAs and introducing GitOps tools such as ArgoCD.