Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 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
40 changes: 24 additions & 16 deletions applications/wg-easy/Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,39 @@ 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"))}}'

# Container workflow configuration
DEV_CONTAINER_REPOSITORY: '{{.DEV_CONTAINER_REPOSITORY | default "docker.io/wg-easy"}}'
DEV_CONTAINER_IMAGE: '{{.DEV_CONTAINER_IMAGE | default "wg-easy"}}'
DEV_CONTAINER_TAG: '{{.DEV_CONTAINER_TAG | default "latest"}}'
DEV_CONTAINER_NAME: '{{.DEV_CONTAINER_NAME | default "wg-easy-dev"}}'
CONTAINER_RUNTIME: '{{.CONTAINER_RUNTIME | default "podman"}}'

tasks:
default:
desc: Show available tasks
Expand Down Expand Up @@ -91,7 +99,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 +120,7 @@ tasks:
true
fi
deps:
- create-cluster
- cluster-create
- verify-kubeconfig

dependencies-update:
Expand All @@ -138,7 +146,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 +155,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 +177,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 +201,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 +221,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 +245,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 +275,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
79 changes: 79 additions & 0 deletions applications/wg-easy/container/Containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Base image for all shared Containerfiles for taskfiles
# Use this image as base image for app specific container 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 \
bash-completion \

# 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 \

# Clean up
&& apt-get purge -y \
curl \
gnupg \
&& 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

# Copy shell completion scripts
COPY container/tool-completions.sh tool-completions.sh

# Copy entrypoint script
COPY container/entrypoint.sh entrypoint.sh
RUN chmod +x entrypoint.sh

# Set working directory
WORKDIR /workspace

# Switch to non-root user
USER devuser

# Set entrypoint
ENTRYPOINT ["/tools/entrypoint.sh", "-l"]
10 changes: 10 additions & 0 deletions applications/wg-easy/container/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

# Uncomment force_color_prompt in bashrc
sed -i 's/#force_color_prompt=yes/force_color_prompt=yes/' $HOME/.bashrc

# Source the tool completions
echo "source /tools/tool-completions.sh" >> $HOME/.bashrc

# Execute the passed command or default to bash
exec "$@"
21 changes: 21 additions & 0 deletions applications/wg-easy/container/tool-completions.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash

# kubectl completion
source <(kubectl completion bash)
alias k=kubectl
complete -o default -F __start_kubectl k

# helm completion
source <(helm completion bash)

# task completion
source <(task --completion bash)

# helmfile completion
source <(helmfile completion bash)

# replicated completion
source <(replicated completion bash)

# gcloud completion
source /usr/share/google-cloud-sdk/completion.bash.inc
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).
- **Container runtime tool** Either [Podman](https://podman.io/docs/installation) (default) or [Docker](https://docs.docker.com/get-docker/) for local development

All other tools will be automatically provided through task commands and 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
87 changes: 87 additions & 0 deletions applications/wg-easy/taskfiles/container.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
version: "3"

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

cmds:
- '{{.CONTAINER_RUNTIME}} build -t {{.DEV_CONTAINER_REPOSITORY}}/{{.DEV_CONTAINER_IMAGE}}:{{.DEV_CONTAINER_TAG}} -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:
DEV_CONTAINER_REPOSITORY: '{{.DEV_CONTAINER_REPOSITORY}}'
DEV_CONTAINER_IMAGE: '{{.DEV_CONTAINER_IMAGE}}'
DEV_CONTAINER_TAG: '{{.DEV_CONTAINER_TAG | default "latest"}}'
DEV_CONTAINER_NAME: '{{.DEV_CONTAINER_NAME}}'
requires:
vars: [DEV_CONTAINER_REPOSITORY, DEV_CONTAINER_IMAGE, DEV_CONTAINER_TAG, DEV_CONTAINER_NAME, REPLICATED_API_TOKEN]

status:
- '{{.CONTAINER_RUNTIME}} ps | grep -q "{{.DEV_CONTAINER_NAME}}"'
cmds:
- |
# Start container with host networking for kubectl port-forward compatibility
CONTAINER_ID=$({{.CONTAINER_RUNTIME}} run --rm --name {{.DEV_CONTAINER_NAME}} -d \
-v $(pwd):/workspace \
-e REPLICATED_API_TOKEN={{ .REPLICATED_API_TOKEN }} \
{{.DEV_CONTAINER_REPOSITORY}}/{{.DEV_CONTAINER_IMAGE}}:{{.DEV_CONTAINER_TAG}} bash -c 'trap "exit 0" TERM; sleep infinity & wait')
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: [DEV_CONTAINER_NAME]
deps:
- start-implementation
cmds:
- echo "Connecting to {{.DEV_CONTAINER_NAME}}..."
- '{{.CONTAINER_RUNTIME}} exec -it {{.DEV_CONTAINER_NAME}} /bin/bash'

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