Skip to content

Commit

Permalink
feat: added local registry support and improved setup (close #353)
Browse files Browse the repository at this point in the history
  • Loading branch information
daveoconnor authored Sep 19, 2024
1 parent cea1602 commit 32de8c7
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 22 deletions.
5 changes: 4 additions & 1 deletion cookiecutter.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,8 @@
}
},
"repo_name": "{{ cookiecutter.project_slug }}",
"repo_url": "git@{{ cookiecutter.source_control_provider }}:{{ cookiecutter.source_control_organization_slug }}/{{ cookiecutter.project_slug }}.git"
"repo_url": "git@{{ cookiecutter.source_control_provider }}:{{ cookiecutter.source_control_organization_slug }}/{{ cookiecutter.project_slug }}.git",
"_copy_without_render": [
"k8s/scripts/kind-with-registry.sh"
]
}
2 changes: 1 addition & 1 deletion scaf
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,8 @@ docker run --rm $DOCKER_RUN_OPTIONS -v "$(pwd):/home/scaf/out" \

# Check if cookiecutter was successful
if [ $? -eq 0 ]; then
kind create cluster --name $CLUSTER_SLUG
cd $COOKIECUTTER_SLUG
make setup
make compile
echo "Dependencies compiled successfully."
pwd
Expand Down
67 changes: 47 additions & 20 deletions {{cookiecutter.project_slug}}/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@ KUBECTL_EXEC_BACKEND = kubectl exec -it $$(kubectl get pods -l app=backend -o js
{% if cookiecutter.create_nextjs_frontend == "y" %}
KUBECTL_EXEC_FRONTEND = kubectl exec -it $$(kubectl get pods -l app=frontend -o jsonpath="{.items[0].metadata.name}") -- bash
{% endif %}
PREREQUISITE_COMMANDS := kubectl tilt kind

# colors
BLUE:=$(shell echo "\033[0;36m")
GREEN:=$(shell echo "\033[0;32m")
YELLOW:=$(shell echo "\033[0;33m")
RED:=$(shell echo "\033[0;31m")
END:=$(shell echo "\033[0m")
# escape character for colors
ESC := \033

# color variables
BLUE := $(ESC)[0;36m
GREEN := $(ESC)[0;32m
YELLOW := $(ESC)[0;33m
RED := $(ESC)[0;31m
END := $(ESC)[0m

PROJECT_SLUG:="{{ cookiecutter.project_slug }}"
REGISTRY_HOSTNAME := localhost
REGISTRY_PORT := 5001

## Release/Deployment Targets

Expand Down Expand Up @@ -66,33 +72,54 @@ backend/requirements/production.txt: compile
backend/requirements/tests.txt: compile

setup:
@echo " $(YELLOW)$(END) Checking if the setup is correct and all prerequisites are installed..."
@printf " $(YELLOW)$(END) Checking if the setup is correct and all prerequisites are installed..."
@MISSING=""; \
for exec in $(PREREQUISITE_COMMANDS); do \
if ! which $$exec > /dev/null 2>&1; then \
MISSING="$$MISSING $$exec"; \
fi; \
done; \
if [ -n "$$MISSING" ]; then \
echo " $(RED)$(END)Missing executables:$$MISSING. These must be installed by you to continue"; \
printf " $(RED)$(END)Missing executables:$$MISSING. These must be installed by you to continue"; \
false; \
else \
echo " $(GREEN)✔️$(END) All prerequisites are installed."; \
printf " $(GREEN)✔️$(END) All prerequisites are installed."; \
fi
@CURRENT_CONTEXT="$$(kubectl config current-context 2>&1)"; \
if [ "$$CURRENT_CONTEXT" = "kind-$(PROJECT_SLUG)" ]; then \
echo " $(GREEN)✔️$(END) The kubectl context is correctly set to kind-$(PROJECT_SLUG). Run 'tilt up' to start your cluster!"; \
CLUSTER_NAME=$(shell echo $(PROJECT_SLUG) | sed 's/_/-/g'); \
NEW_CONTEXT=kind-$$CLUSTER_NAME; \
CLUSTER_EXISTS = $(shell kind get clusters | grep -w $$CLUSTER_NAME$$ || true); \
if [ -z "$$CLUSTER_EXISTS" ]; then \
printf " $(YELLOW)$(END) No cluster found for $$CLUSTER_NAME. Creating your cluster. Please wait, this may take a couple of minutes on a slower machine..."; \
k8s/scripts/kind-with-registry.sh $$CLUSTER_NAME > /tmp/scaf_cluster.log 2>&1; \
printf " $(GREEN)✔️$(END) $$NEW_CONTEXT cluster and context created."; \
printf " $(BLUE)🗣️ $(END) Pre-loading upstream images into cluster."; \
docker pull postgres:16; \
docker pull redis:6.0.5; \
docker pull mailhog/mailhog:v1.0.0; \
kind load docker-image postgres:16 --name $$CLUSTER_NAME; \
kind load docker-image redis:6.0.5 --name $$CLUSTER_NAME; \
kind load docker-image mailhog/mailhog:v1.0.0 --name $$CLUSTER_NAME; \
printf " $(GREEN)✔️$(END) $$NEW_CONTEXT cluster and context created."; \
printf " $(BLUE)🗣️ Remember, you can safely run \"make setup\" any time to switch between Scaf projects.$(END)"; \
printf " $(GREEN)✔️$(END) Finished! Run 'tilt up' to start your cluster! "; \
else \
echo " $(YELLOW)$(END) Current kubectl context is not 'kind-$(PROJECT_SLUG)'. Switching context now..."; \
if [ -z "$$(kubectl config get-contexts -o name | grep -w 'kind-$(PROJECT_SLUG)$$')" ]; then \
echo " $(YELLOW)$(END) No context found for kind-$(PROJECT_SLUG). Creating one. Please wait, this may take a couple of minutes on a slower machine..."; \
kind create cluster --name $(PROJECT_SLUG) 1>/dev/null 2>/tmp/scaf_error.log; \
echo " $(GREEN)✔️$(END) kind-$(PROJECT_SLUG) cluster and context created."; \
echo " $(BLUE)🗣️ Remember, you can safely run \"make setup\" any time to switch between Scaf projects.$(END)"; \
if [ "$$CURRENT_CONTEXT" = "$$NEW_CONTEXT" ]; then \
printf " $(GREEN)✔️$(END) The kubectl context is correctly set to '$$NEW_CONTEXT'. Run 'tilt up' to start your cluster!"; \
else \
kubectl config use-context $$NEW_CONTEXT 1>/dev/null 2>/tmp/scaf_error.log; \
printf " $(GREEN)✔️$(END) Context switched to $$NEW_CONTEXT. Run 'tilt up' to start your cluster! "; \
fi; \
kubectl config use-context kind-$(PROJECT_SLUG) 1>/dev/null 2>/tmp/scaf_error.log; \
echo " $(GREEN)✔️$(END) Context switched to kind-$(PROJECT_SLUG). Run 'tilt up' to start your cluster! "; \
fi
fi; \

list-local-docker-images:
@printf " $(YELLOW)$(END) Listing local docker images..."
@curl -s "$(REGISTRY_HOSTNAME):$(REGISTRY_PORT)/v2/_catalog" | jq -r '.repositories[]' | while read REPO; do \
echo "Repository: $$REPO"; \
curl -s "$(REGISTRY_HOSTNAME):$(REGISTRY_PORT)/v2/$$REPO/tags/list" | jq -r '.tags[]' | while read TAG; do \
echo " Tag: $$TAG"; \
done; \
done

outdated: ## Show all the outdated packages with their latest versions in the container
$(KUBECTL_EXEC_BACKEND) -c "pip list --outdated"
Expand Down
70 changes: 70 additions & 0 deletions {{cookiecutter.project_slug}}/k8s/scripts/kind-with-registry.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/bin/sh
set -o errexit

# SCAF NOTE:
# This is a modified version of the script from the kind project.
# The original script can be found at:
# https://kind.sigs.k8s.io/docs/user/local-registry/

# 1. Create registry container unless it already exists
cluster_name="$1"
reg_name="scaf-registry"
reg_port='5001'
if [ "$(docker inspect -f '{{.State.Running}}' "${reg_name}" 2>/dev/null || true)" != 'true' ]; then
docker run \
-d --restart=always -p "${reg_port}:5000" --network bridge --name "${reg_name}" \
registry:2
fi

# 2. Create kind cluster with containerd registry config dir enabled
# TODO: kind will eventually enable this by default and this patch will
# be unnecessary.
#
# See:
# https://github.com/kubernetes-sigs/kind/issues/2875
# https://github.com/containerd/containerd/blob/main/docs/cri/config.md#registry-configuration
# See: https://github.com/containerd/containerd/blob/main/docs/hosts.md
cat <<EOF | kind create cluster --name="$cluster_name" --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
containerdConfigPatches:
- |-
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/containerd/certs.d"
EOF
echo "Context: $(kubectl config current-context)"
# 3. Add the registry config to the nodes
#
# This is necessary because localhost resolves to loopback addresses that are
# network-namespace local.
# In other words: localhost in the container is not localhost on the host.
#
# We want a consistent name that works from both ends, so we tell containerd to
# alias localhost:${reg_port} to the registry container when pulling images
REGISTRY_DIR="/etc/containerd/certs.d/localhost:${reg_port}"
for node in $(kind get nodes -n "${cluster_name}"); do
docker exec "${node}" mkdir -p "${REGISTRY_DIR}"
cat <<EOF | docker exec -i "${node}" cp /dev/stdin "${REGISTRY_DIR}/hosts.toml"
[host."http://${reg_name}:5000"]
EOF
done

# 4. Connect the registry to the cluster network if not already connected
# This allows kind to bootstrap the network but ensures they're on the same network
if [ "$(docker inspect -f='{{json .NetworkSettings.Networks.kind}}' "${reg_name}")" = 'null' ]; then
docker network connect "kind" "${reg_name}"
fi

# 5. Document the local registry
# https://github.com/kubernetes/enhancements/tree/master/keps/sig-cluster-lifecycle/generic/1755-communicating-a-local-registry
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: local-registry-hosting
namespace: kube-public
data:
localRegistryHosting.v1: |
host: "localhost:${reg_port}"
help: "https://kind.sigs.k8s.io/docs/user/local-registry/"
EOF

0 comments on commit 32de8c7

Please sign in to comment.