Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
6fe352f
feat: Dockerfile containing all dependencies for tasks
banjoh Apr 23, 2025
48d112b
download helmfile
banjoh Apr 24, 2025
b26044d
feat: Dockerfile containing all dependencies for tasks
banjoh Apr 23, 2025
2ef4633
download helmfile
banjoh Apr 24, 2025
dac6b1f
Merge branch 'em/dockerize-wg-easy-dependencies' of github.com:banjoh…
banjoh Apr 25, 2025
dfe10c3
Add initial docker env taskfile
banjoh Apr 25, 2025
30c6a4c
Move docker tasks into wg-easy application
banjoh Apr 25, 2025
3e5c1cd
Update dev documentation
banjoh Apr 25, 2025
30b7781
Copy replicated auth token to container
banjoh Apr 25, 2025
e26440e
Update dev documentation
banjoh Apr 25, 2025
0e669a9
Fix grammer
banjoh Apr 25, 2025
0da51be
Add SHELL env required by replicated shell subcommand
banjoh Apr 25, 2025
a75abac
Default to Podman, allow Docker optionally (#54)
scottrigby Apr 28, 2025
e77f4f0
Prepend DEV to dev container variables
banjoh Apr 28, 2025
68ecc8d
Changes as per review comments
banjoh Apr 28, 2025
cdcc991
Add shell completions and some colour to terminal
banjoh Apr 28, 2025
a05d485
Remove duplicate completion
banjoh Apr 28, 2025
c8566f2
Update applications/wg-easy/container/Containerfile
banjoh Apr 29, 2025
b823872
Update applications/wg-easy/docs/development-workflow.md
banjoh Apr 29, 2025
4e7619e
Remove unnecessary shell-implementation task
banjoh Apr 29, 2025
6649ed7
Improvements in Containerfile
banjoh Apr 29, 2025
cba7c04
Remove unnecessary comment
banjoh Apr 29, 2025
5b4b5aa
Build and publish wg-easy tools image to ghcr
banjoh Apr 29, 2025
3c23789
Update paths to check in workflow file
banjoh Apr 29, 2025
1226492
Fix repo name
banjoh Apr 29, 2025
629cb1e
Push in PR
banjoh Apr 29, 2025
0825b3e
Publish multiarch images
banjoh Apr 29, 2025
8889f47
Download architecture specific binaries
banjoh Apr 29, 2025
83c1dc0
Only push when in main branch
banjoh Apr 29, 2025
4de1ef6
Check if image exists locally before pulling or building
banjoh Apr 30, 2025
a3ef59e
Remove step to build image in docs
banjoh Apr 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 21 additions & 16 deletions applications/wg-easy/Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,36 @@ version: "3"

includes:
utils: ./taskfiles/utils.yml
dev: ./taskfiles/container.yml

vars:
# Application configuration
APP_NAME: '{{.REPLICATED_APP | default "wg-easy"}}'

# Cluster configuration
CLUSTER_NAME: '{{.CLUSTER_NAME | default "test-cluster"}}'
K8S_VERSION: '{{.K8S_VERSION | default "1.32.2"}}'
DISK_SIZE: '{{.DISK_SIZE | default "100"}}'
INSTANCE_TYPE: '{{.INSTANCE_TYPE | default "r1.small"}}'
DISTRIBUTION: '{{.DISTRIBUTION | default "k3s"}}'
KUBECONFIG_FILE: './{{.CLUSTER_NAME}}.kubeconfig'

# Ports configuration
EXPOSE_PORTS:
- port: 30443
protocol: https
- port: 30080
protocol: http

# GCP default configuration
GCP_PROJECT: '{{.GCP_PROJECT | default "replicated-qa"}}'
GCP_ZONE: '{{.GCP_ZONE | default "us-central1-a"}}'
VM_NAME: '{{.VM_NAME | default (printf "%s-dev" (or (env "GUSER") "user"))}}'

# Docker workflow configuration
IMAGE_NAME: ttl.sh/wg-easy-dev
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We really shouldn't be using ttl.sh here, it's fine for development but it needs to be available somewhere else for the actual workflow. Is this currently just for you to test and you intend to move it later?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is currently for test until we decide on

  • if we need to host this image. We need to weigh the need to host the image vs users needing to build the image which take a minute.
  • what OCI registry - docker hub? replicated? all of the above?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we build the image and have it pushed to ghcr.io right here on this repo?
I'm fine with starting with a local build and following up with the auto-build on ghcr or if it's easy enough just build it anytime the Containerfile changes on merge to main.

I added a podman based image build/push on troubleshoot-mcp-server which might be very close to what you would need. https://github.com/chris-sanders/troubleshoot-mcp-server/blob/main/.github/workflows/publish-container.yaml

CONTAINER_NAME: wg-easy-dev

tasks:
default:
desc: Show available tasks
Expand Down Expand Up @@ -91,7 +96,7 @@ tasks:
echo "Removing old kubeconfig file"
rm -f {{.KUBECONFIG_FILE}}
fi
fi
fi

setup-kubeconfig:
desc: Get kubeconfig and prepare cluster for application deployment
Expand All @@ -112,7 +117,7 @@ tasks:
true
fi
deps:
- create-cluster
- cluster-create
- verify-kubeconfig

dependencies-update:
Expand All @@ -138,7 +143,7 @@ tasks:
if [ -z "$CLUSTER_ID" ]; then
exit 1
fi

# Check if all ports are already exposed
expected_count={{len .EXPOSE_PORTS}}
port_checks=""
Expand All @@ -147,7 +152,7 @@ tasks:
{{end}}
# Remove trailing "or "
port_checks="${port_checks% or }"

PORT_COUNT=$(replicated cluster port ls $CLUSTER_ID --output json | jq -r ".[] | select($port_checks) | .upstream_port" | wc -l | tr -d ' ')
[ "$PORT_COUNT" -eq "$expected_count" ]
cmds:
Expand All @@ -169,10 +174,10 @@ tasks:
echo "Error: Could not find cluster with name {{.CLUSTER_NAME}}"
exit 1
fi

# Get exposed URLs
ENV_VARS=$(task utils:port-operations OPERATION=getenv CLUSTER_NAME={{.CLUSTER_NAME}})

# Deploy with helmfile
echo "Using $ENV_VARS"
eval "KUBECONFIG={{.KUBECONFIG_FILE}} $ENV_VARS helmfile sync --wait"
Expand All @@ -193,7 +198,7 @@ tasks:
echo "No clusters found with name {{.CLUSTER_NAME}}"
exit 0
fi

for id in $CLUSTER_IDS; do
echo "Deleting cluster ID: $id"
replicated cluster rm "$id"
Expand All @@ -213,7 +218,7 @@ tasks:
- echo "Preparing release files..."
- rm -rf ./release
- mkdir -p ./release

# Copy all non-config.yaml files
- echo "Copying non-config YAML files to release folder..."
- find . -path '*/replicated/*.yaml' -not -name 'config.yaml' -exec cp {} ./release/ \;
Expand All @@ -237,27 +242,27 @@ tasks:
yq '.spec.chart.chartVersion = strenv(version) | .spec.chart.chartVersion style="single"' $directory/$helmChartName | tee release/$helmChartName

done < <(find . -maxdepth 2 -mindepth 2 -type d -name replicated)

# Merge config.yaml files
- echo "Merging config.yaml files..."
- |
# Start with an empty config file
echo "{}" > ./release/config.yaml

# Merge all app config.yaml files first (excluding root replicated)
for config_file in $(find . -path '*/replicated/config.yaml' | grep -v "^./replicated/"); do
echo "Merging $config_file..."
yq eval-all '. as $item ireduce ({}; . * $item)' ./release/config.yaml "$config_file" > ./release/config.yaml.new
mv ./release/config.yaml.new ./release/config.yaml
done

# Merge root config.yaml last
if [ -f "./replicated/config.yaml" ]; then
echo "Merging root config.yaml last..."
yq eval-all '. as $item ireduce ({}; . * $item)' ./release/config.yaml "./replicated/config.yaml" > ./release/config.yaml.new
mv ./release/config.yaml.new ./release/config.yaml
fi

# Package Helm charts
- echo "Packaging Helm charts..."
- |
Expand All @@ -267,7 +272,7 @@ tasks:
# Navigate to chart directory, package it, and move the resulting .tgz to release folder
(cd "$chart_dir" && helm package . && mv *.tgz ../release/)
done

- echo "Release files prepared in ./release/ directory"
deps:
- update-version
Expand Down
68 changes: 68 additions & 0 deletions applications/wg-easy/container/Containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Base image for all shared Dockerfiles for taskfiles
# Use this image as base image for app specific docker files
FROM --platform=$BUILDPLATFORM ubuntu:24.04

ARG TARGETOS
ARG TARGETARCH

WORKDIR /tools

# Set environment variables
ENV DEBIAN_FRONTEND=noninteractive \
HOME=/home/devuser \
SHELL=/bin/bash

# Install CLI tools
RUN apt-get update && apt-get install -y \
curl \
jq \
yq \
gnupg \
sudo \

# Install Helm
&& curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash \

# Install kubectl
&& curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \
&& chmod +x kubectl \
&& mv kubectl /usr/local/bin/ \

# Install Task
&& sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin \

# Install Helmfile
&& curl -Ls $(curl -s https://api.github.com/repos/helmfile/helmfile/releases/latest \
| grep "browser_download_url.*linux_amd64.tar.gz" \
| cut -d : -f 2,3 \
| tr -d \") -o helmfile.tar.gz \
&& tar xf helmfile.tar.gz helmfile && rm helmfile.tar.gz \
&& mv helmfile /usr/local/bin/helmfile \

# Install Replicated CLI
&& curl -Ls $(curl -s https://api.github.com/repos/replicatedhq/replicated/releases/latest \
| grep "browser_download_url.*linux_amd64.tar.gz" \
| cut -d : -f 2,3 \
| tr -d \") -o replicated.tar.gz \
&& tar xf replicated.tar.gz replicated && rm replicated.tar.gz \
&& mv replicated /usr/local/bin/replicated \

# Install Google Cloud CLI
&& echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list \
&& curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg \
&& apt-get update \
&& apt-get install google-cloud-cli -y \
&& rm -rf /var/lib/apt/lists/*

# Create a non-root user for better security
RUN groupadd -r devuser \
&& useradd -r -g devuser -m -s /bin/bash devuser \
&& echo "devuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/devuser

# Set working directory
WORKDIR /app

# Switch to non-root user
USER devuser

CMD ["bash"]
24 changes: 15 additions & 9 deletions applications/wg-easy/docs/development-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,9 @@ The core philosophy of this workflow is to start simple and add complexity incre
Before starting the development workflow, ensure you have the following tools installed:

- **Task:** The task runner used in this project. ([Installation Guide](https://taskfile.dev/installation/))
- **Replicated CLI:** For managing test clusters and application releases. ([Installation Guide](https://docs.replicated.com/reference/replicated-cli-installing))
- **Helm:** The Kubernetes package manager. ([Installation Guide](https://helm.sh/docs/intro/install/))
- **Helmfile:** For orchestrating Helm chart deployments. ([Installation Guide](https://github.com/helmfile/helmfile#installation))
- **kubectl:** The Kubernetes command-line tool. ([Installation Guide](https://kubernetes.io/docs/tasks/tools/install-kubectl/))
- **jq:** A command-line JSON processor. ([Download Page](https://stedolan.github.io/jq/download/))
- **yq:** A command-line YAML processor. ([Installation Guide](https://github.com/mikefarah/yq#install))
- **gcloud CLI:** Google Cloud command-line interface (optional, only required for GCP-specific tasks). ([Installation Guide](https://cloud.google.com/sdk/docs/install))
- **Standard Unix Utilities:** `find`, `xargs`, `grep`, `awk`, `wc`, `tr`, `cp`, `mv`, `rm`, `mkdir`, `echo`, `sleep`, `test`, `eval` (typically available by default on Linux and macOS).
- **Docker:** Container runtime for local development. ([Installation Guide](https://docs.docker.com/get-docker/))

All other tools will be automatically provided through task commands and Docker containers.

## Workflow Stages

Expand Down Expand Up @@ -97,6 +92,17 @@ Configure chart values and create or modify templates.

### Stage 3: Local Validation with helm template

> [!IMPORTANT]
> Tools required by tasks in this project will be made available in a container. Run the commands below to start the dev environment

```
# Build tools image. Run this command once.
task dev:build-image

# Open shell to execute tasks
task dev:shell
```

Validate chart templates locally without deploying to a cluster.

1. Run helm template to render the chart and inspect manifests:
Expand Down Expand Up @@ -177,7 +183,7 @@ Test multiple charts working together using Helmfile orchestration.
# Check if issuers are correctly using cert-manager
kubectl get clusterissuers
kubectl get issuers -A

# Verify Traefik routes
kubectl get ingressroutes -A
```
Expand Down
90 changes: 90 additions & 0 deletions applications/wg-easy/taskfiles/container.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
version: "3"

# Development environment tasks
tasks:
build-image:
desc: Build development Docker image
vars:
IMAGE_NAME: '{{.IMAGE_NAME}}'
IMAGE_TAG: '{{.IMAGE_TAG | default "latest"}}'
CONTAINERFILE: '{{.CONTAINERFILE | default "./container/Containerfile"}}'
BUILD_ARGS: '{{.BUILD_ARGS | default ""}}'
requires:
vars: [IMAGE_NAME, IMAGE_TAG, CONTAINERFILE]

cmds:
- docker build -t {{.IMAGE_NAME}} -f {{.CONTAINERFILE}} .

start:
desc: Start development container in background
silent: true
cmds:
- task: start-implementation

# Start development container in background.
# It's internal because it's used by shell and start tasks.
start-implementation:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not following why can't this all just be in the "start" task? Task can call and require each other what does having an internal task buy you here if the real start task is just calling the internal one anyway?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've DRY'd this bit some more

desc: Start development container in background
silent: true
run: once
internal: true
vars:
IMAGE_NAME: '{{.IMAGE_NAME}}'
CONTAINER_NAME: '{{.CONTAINER_NAME}}'
IMAGE_TAG: '{{.IMAGE_TAG | default "latest"}}'
requires:
vars: [IMAGE_NAME, CONTAINER_NAME, REPLICATED_API_TOKEN]

status:
- docker ps | grep -q "{{.CONTAINER_NAME}}"
cmds:
- |
# Start container with host networking for kubectl port-forward compatibility
CONTAINER_ID=$(docker run --rm --name {{.CONTAINER_NAME}} -d \
-v $(pwd):/workspace \
-e HOME=/home/devuser \
-e USER=devuser \
-e REPLICATED_API_TOKEN={{ .REPLICATED_API_TOKEN }} \
-w /workspace \
{{.IMAGE_NAME}}:{{.IMAGE_TAG}} bash -c 'trap "exit" TERM; while :; do sleep 0.1; done')
if [ $? -eq 0 ]; then
echo "Development container started successfully with ID: $CONTAINER_ID"
else
echo "Failed to start development container"
exit 1
fi
shell:
desc: Attach to development container shell
silent: true
requires:
vars: [CONTAINER_NAME]
deps:
- start-implementation
cmds:
- echo "Connecting to {{.CONTAINER_NAME}}..."
- docker exec -it {{.CONTAINER_NAME}} /bin/bash

stop:
desc: Stop development container
silent: true
requires:
vars: [CONTAINER_NAME]
cmds:
- |
if docker ps | grep -q "{{.CONTAINER_NAME}}"; then
echo "Stopping {{.CONTAINER_NAME}} development container..."
docker stop {{.CONTAINER_NAME}}
else
echo "Container {{.CONTAINER_NAME}} is not running"
fi
restart:
desc: Restart development container
silent: true
requires:
vars: [CONTAINER_NAME]
cmds:
- task: stop
- task: start