kubernetes deployment strategy notes

This commit is contained in:
Super User
2026-10-30 17:18:18 -07:00
parent 504f81de76
commit 35c9d9fd36
57 changed files with 1677 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
I used AI (Gemini) to take a long collection of commands required to prepare a node to run kubernetes and turned that into an Ansible playbook in order to make the process faster and easier to repeat in the future.
+2
View File
@@ -0,0 +1,2 @@
[defaults]
host_key_checking = False
+130
View File
@@ -0,0 +1,130 @@
---
- name: Prepare node for Kubernetes with CRI-O
hosts: all
become: true
tasks:
- name: Disable and stop firewalld
ansible.builtin.systemd:
name: firewalld
state: stopped
enabled: false
- name: Set SELinux to permissive mode in config
ansible.builtin.lineinfile:
path: /etc/selinux/config
regexp: '^SELINUX='
line: 'SELINUX=permissive'
- name: Set SELinux to permissive runtime immediately
ansible.posix.selinux:
policy: targeted
state: permissive
- name: Configure kernel modules to load on boot
ansible.builtin.copy:
dest: /etc/modules-load.d/k8s.conf
content: |
overlay
br_netfilter
mode: '0644'
- name: Load kernel modules immediately
community.general.modprobe:
name: "{{ item }}"
state: present
loop:
- overlay
- br_netfilter
- name: Configure sysctl parameters for Kubernetes networking
ansible.posix.sysctl:
name: "{{ item.key }}"
value: "{{ item.value }}"
sysctl_file: /etc/sysctl.d/k8s.conf
state: present
reload: true
loop:
- { key: 'net.bridge.bridge-nf-call-iptables', value: '1' }
- { key: 'net.bridge.bridge-nf-call-ip6tables', value: '1' }
- { key: 'net.ipv4.ip_forward', value: '1' }
- name: Add Kubernetes YUM repository
ansible.builtin.yum_repository:
name: kubernetes
description: Kubernetes
baseurl: https://pkgs.k8s.io/core:/stable:/v1.37/rpm/
enabled: true
gpgcheck: true
gpgkey: https://pkgs.k8s.io/core:/stable:/v1.37/rpm/repodata/repomd.xml.key
- name: Add CRI-O YUM repository
ansible.builtin.yum_repository:
name: cri-o
description: CRI-O
baseurl: https://download.opensuse.org/repositories/isv:/cri-o:/stable:/v1.37/rpm/
enabled: true
gpgcheck: true
gpgkey: https://download.opensuse.org/repositories/isv:/cri-o:/stable:/v1.37/rpm/repodata/repomd.xml.key
- name: Install CRI-O, Podman, and Kubernetes packages
ansible.builtin.dnf:
name:
- cri-o
- cri-tools
- podman
- kubelet
- kubeadm
- kubectl
state: present
- name: Ensure CRI-O configuration drop-in directory exists
ansible.builtin.file:
path: /etc/crio/crio.conf.d
state: directory
mode: '0755'
- name: Configure CRI-O cgroup manager
ansible.builtin.copy:
dest: /etc/crio/crio.conf.d/10-cgroup-manager.conf
content: |
[crio.runtime]
conmon_cgroup = "pod"
cgroup_manager = "systemd"
mode: '0644'
notify: Restart crio
- name: Configure kubelet runtime endpoint
ansible.builtin.copy:
dest: /etc/sysconfig/kubelet
content: |
KUBELET_EXTRA_ARGS="--container-runtime-endpoint=unix:///var/run/crio/crio.sock"
mode: '0644'
notify: Restart kubelet
- name: Enable and start CRI-O
ansible.builtin.systemd:
name: crio
state: started
enabled: true
daemon_reload: true
- name: Enable and start kubelet
ansible.builtin.systemd:
name: kubelet
state: started
enabled: true
- name: Reboot the server
ansible.builtin.reboot:
reboot_timeout: 600
handlers:
- name: Restart crio
ansible.builtin.systemd:
name: crio
state: restarted
- name: Restart kubelet
ansible.builtin.systemd:
name: kubelet
state: restarted
+7
View File
@@ -0,0 +1,7 @@
[k8s_nodes]
control-plane.k8s.lab.cudanet.org
compute-node-1.k8s.lab.cudanet.org
compute-node-2.k8s.lab.cudanet.org
[k8s_nodes:vars]
ansible_user=ansible
+1
View File
@@ -0,0 +1 @@
the initial deployment and configuration of ArgoCD on my cluster was a pretty straightforward helm chart deployment. However, I did run into some issues with how ArgoCD handles SSL that I leveraged AI (Gemini) to help quickly troubleshoot. Beyond that, creating a project, adding a repo, creating an application and deploying nginx was mostly handled referring to my personal notes.
+19
View File
@@ -0,0 +1,19 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
annotations:
name: letsencrypt
namespace: argocd
spec:
commonName: 'argocd.k8s.lab.cudanet.org'
dnsNames:
- 'argocd.k8s.lab.cudanet.org'
duration: 2160h0m0s
issuerRef:
kind: ClusterIssuer
name: letsencrypt
renewBefore: 360h0m0s
secretName: letsencrypt
usages:
- server auth
- client auth
+24
View File
@@ -0,0 +1,24 @@
NAME: argocd
LAST DEPLOYED: Fri Oct 30 13:32:17 2026
NAMESPACE: argocd
STATUS: deployed
REVISION: 1
DESCRIPTION: Install complete
TEST SUITE: None
NOTES:
In order to access the server UI you have the following options:
1. kubectl port-forward service/argocd-server -n argocd 8080:443
and then open the browser on http://localhost:8080 and accept the certificate
2. enable ingress in the values file `server.ingress.enabled` and either
- Add the annotation for ssl passthrough: https://argo-cd.readthedocs.io/en/stable/operator-manual/ingress/#option-1-ssl-passthrough
- Set the `configs.params."server.insecure"` in the values file and terminate SSL at your ingress: https://argo-cd.readthedocs.io/en/stable/operator-manual/ingress/#option-2-multiple-ingress-objects-and-hosts
After reaching the UI the first time you can login with username: admin and the random password generated during the installation. You can find the password by running:
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
(You should delete the initial secret afterwards as suggested by the Getting Started Guide: https://argo-cd.readthedocs.io/en/stable/getting_started/#4-login-using-the-cli)
+37
View File
@@ -0,0 +1,37 @@
apiVersion: traefik.io/v1alpha1
kind: ServersTransport
metadata:
name: argocd-server-transport
namespace: argocd
spec:
insecureSkipVerify: true
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: argocd-server
namespace: argocd
spec:
entryPoints:
- websecure
routes:
# 1. gRPC routing for Argo CD CLI and API clients
- match: Host(`argocd.k8s.lab.cudanet.org`) && Headers(`Content-Type`, `application/grpc`)
kind: Rule
priority: 11
services:
- name: argocd-server
port: 443
scheme: https
serversTransport: argocd-server-transport
# 2. Standard Web UI traffic
- match: Host(`argocd.k8s.lab.cudanet.org`)
kind: Rule
priority: 10
services:
- name: argocd-server
port: 443
scheme: https
serversTransport: argocd-server-transport
tls:
secretName: argocd-tls-cert # Replace with your TLS Secret, or omit if using Traefik default cert / cert-resolver
+1
View File
@@ -0,0 +1 @@
Ci4Jz6xJVj9Zg3ER
+1
View File
@@ -0,0 +1 @@
eyJhbGciOiJSUzI1NiIsImtpZCI6InJTeEp1ZTlwbzZnUkduNk5hN2Fhc0hMTHQtRTM1RlZlcGJZX2J4OS1GSFkifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzkzMzk2MzcyLCJpYXQiOjE3OTMzOTI3NzIsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwianRpIjoiMDlmZThkZWMtNmZlMy00NzMwLWEzNGYtNTlkNGNiNTE5Yzg2Iiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJoZWFkbGFtcCIsInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJoZWFkbGFtcCIsInVpZCI6IjMxZjYyYzRlLWRjNjMtNDQwZi05ZWU4LTBhNDY0YTU2MTNmMyJ9fSwibmJmIjoxNzkzMzkyNzcyLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6aGVhZGxhbXA6aGVhZGxhbXAifQ.t_zHac1qGD2ea3VasvoFRUN1KpN8JR-YenjOcUdTPVIVAY4E2RAveveQKUPVQ_kI-p0NEUfs_cW_p6zZMcOMicib40BS-fVhgCTvtYo2qkmUXRR-sjvNLnk69z-QF_1d-QghCvFm0kSZosyJad_HNqiFwtwhJ5w4fYd_uiAu7zHQuBXLQsLDhvuHkkp4E5zrmZomFx-XQSdAf6YoROuVpz0aEAuAK9dMRc5tmb7u21m11OhemP1DJ43efHu0vV--xLCG738jF_yqonLm7Aj4DzS9-vyNBbaji5Ola57UQLKNeDFdnzEvtvGIenuXMLwpfE9WRfsXYUngFFJKZ0M2sA
+5
View File
@@ -0,0 +1,5 @@
no AI here. Just a copy + paste from my notes
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
just make sure that the kubeadm-config.yaml specifies the corred pod network subnet 192.168.0.0/16 for Calico.
+1
View File
@@ -0,0 +1 @@
no AI here - just a quick google search. Once cert-manager was installed via helm, adding a cluster-issuer and requesting certs came from my personal notes having used cert-manager for years.
+19
View File
@@ -0,0 +1,19 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
annotations:
name: letsencrypt
namespace: cert-manager
spec:
commonName: '*.k8s.lab.cudanet.org'
dnsNames:
- '*.k8s.lab.cudanet.org'
duration: 2160h0m0s
issuerRef:
kind: ClusterIssuer
name: letsencrypt
renewBefore: 360h0m0s
secretName: letsencrypt
usages:
- server auth
- client auth
+19
View File
@@ -0,0 +1,19 @@
apiVersion: v1
data:
api-key: OWVjMTdmYzA0MjJlN2VlZmQxNDdmMmU2ZGE5MmQxMjY2OGZiNQ==
kind: Secret
metadata:
annotations:
name: cloudflare-api-key-secret
namespace: cert-manager
type: Opaque
---
apiVersion: v1
data:
api-token: NEpmdEMxRm5acGN4U2t2OWFWNk1QWEQ4SEN4eVlIblAyWDhCcTNxZg==
kind: Secret
metadata:
annotations:
name: cloudflare-api-token-secret
namespace: cert-manager
type: Opaque
+22
View File
@@ -0,0 +1,22 @@
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
annotations:
name: letsencrypt
spec:
acme:
email: ryancuda@protonmail.com
privateKeySecretRef:
name: acme-key
server: https://acme-v02.api.letsencrypt.org/directory
solvers:
- dns01:
cloudflare:
apiKeySecretRef:
key: api-key
name: cloudflare-api-key-secret
email: ryancuda@protonmail.com
cnameStrategy: Follow
selector:
dnsZones:
- lab.cudanet.org
+11
View File
@@ -0,0 +1,11 @@
# 1. Add the official Jetstack Helm repository
helm repo add jetstack https://charts.jetstack.io
# 2. Update your local Helm chart repository cache
helm repo update
# 3. Install cert-manager and automatically create its Custom Resource Definitions (CRDs)
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set crds.enabled=true
+1
View File
@@ -0,0 +1 @@
no AI used here. I've been using democratic-csi in my lab for years. Just a simple, straightforward helm deployment.
+61
View File
@@ -0,0 +1,61 @@
csiDriver:
name: "org.democratic-csi.iscsi"
storageClasses:
- name: iscsi
defaultClass: false
reclaimPolicy: Delete
volumeBindingMode: Immediate
allowVolumeExpansion: true
parameters:
fsType: ext4
mountOptions: []
secrets:
provisioner-secret:
controller-publish-secret:
node-stage-secret:
node-publish-secret:
controller-expand-secret:
volumeSnapshotClasses:
- name: iscsi-snapclass
parameters:
detachedSnapshots: "true"
secrets:
snapshotter-secret:
driver:
config:
driver: zfs-generic-iscsi
driver: zfs-generic-iscsi
sshConnection:
host: 10.4.0.100
port: 22
username: root
password: "<changeme>"
zfs:
cli:
paths:
zfs: /usr/sbin/zfs
zpool: /usr/sbin/zpool
sudo: /usr/bin/sudo
chroot: /usr/sbin/chroot
datasetParentName: pool0/vols
detachedSnapshotsDatasetParentName: pool0/snaps
zvolCompression:
zvolDedup:
zvolEnableReservation: false
zvolBlocksize:
iscsi:
shareStrategy: "targetCli"
shareStrategyTargetCli:
#sudoEnabled: true
basename: "iqn.1994-05.com.redhat:d9e2323cca59"
tpg:
attributes:
authentication: 0
generate_node_acls: 1
cache_dynamic_acls: 1
demo_mode_write_protect: 0
auth:
targetPortal: "10.4.0.100:3260"
interface: ""
namePrefix:
nameSuffix:
+53
View File
@@ -0,0 +1,53 @@
csiDriver:
name: "org.democratic-csi.nfs"
storageClasses:
- name: nfs
defaultClass: false
reclaimPolicy: Delete
volumeBindingMode: Immediate
allowVolumeExpansion: true
parameters:
fsType: nfs
mountOptions: []
secrets:
provisioner-secret:
controller-publish-secret:
node-stage-secret:
node-publish-secret:
controller-expand-secret:
volumeSnapshotClasses:
- name: nfs-snapclass
parameters:
detachedSnapshots: "true"
secrets:
snapshotter-secret:
driver:
config:
driver: zfs-generic-nfs
sshConnection:
host: 10.4.0.100
port: 22
username: root
password: "<changeme>"
zfs:
cli:
paths:
zfs: /usr/sbin/zfs
zpool: /usr/sbin/zpool
sudo: /usr/bin/sudo
chroot: /usr/sbin/chroot
datasetParentName: pool0/k8s/nfs/volumes
detachedSnapshotsDatasetParentName: pool0/k8s/nfs/snapshots
datasetEnableQuotas: true
datasetEnableReservation: false
datasetPermissionsMode: "0777"
datasetPermissionsUser: 0
datasetPermissionsGroup: 0
nfs:
shareStrategy: "setDatasetProperties"
shareStrategySetDatasetProperties:
properties:
sharenfs: "rw,no_subtree_check,no_root_squash"
#sharenfs: "on"
# share: ""
shareHost: "10.4.0.100"
+16
View File
@@ -0,0 +1,16 @@
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-nfs
namespace: default
annotations:
volume.beta.kubernetes.io/storage-provisioner: org.democratic-csi.nfs
volume.kubernetes.io/storage-provisioner: org.democratic-csi.nfs
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
storageClassName: nfs
volumeMode: Filesystem
+31
View File
@@ -0,0 +1,31 @@
firewall-cmd --permanent --add-masquerade
firewall-cmd --permanent --add-port=6443/tcp # Kubernetes API Server
firewall-cmd --permanent --add-port=2379-2380/tcp # etcd server client API
firewall-cmd --permanent --add-port=10250/tcp # Kubelet API
firewall-cmd --permanent --add-port=10259/tcp # kube-scheduler
firewall-cmd --permanent --add-port=10257/tcp # kube-controller-manager
firewall-cmd --permanent --add-port=8472/udp # Flannel VXLAN overlay
firewall-cmd --permanent --add-port=51820/udp # Flannel WireGuard (optional/fallback)
firewall-cmd --permanent --zone=trusted --add-source=10.3.0.0/24 # Lab Node Subnet
firewall-cmd --permanent --zone=trusted --add-source=10.244.0.0/16 # Pod CIDR
firewall-cmd --permanent --zone=trusted --add-source=10.96.0.0/12 # Service CIDR
firewall-cmd --permanent --zone=trusted --add-interface=cni0
firewall-cmd --permanent --zone=trusted --add-interface=flannel.1
firewall-cmd --reload
firewall-cmd --permanent --add-masquerade
firewall-cmd --permanent --add-port=6443/tcp # API Server
firewall-cmd --permanent --add-port=2379-2380/tcp # etcd
firewall-cmd --permanent --add-port=10250/tcp # Kubelet API
firewall-cmd --permanent --add-port=10259/tcp # kube-scheduler
firewall-cmd --permanent --add-port=10257/tcp # kube-controller-manager
firewall-cmd --permanent --add-port=179/tcp # Calico BGP
firewall-cmd --permanent --add-port=4789/udp # Calico VXLAN (if used instead of IPIP)
firewall-cmd --permanent --add-port=5473/tcp # Typha (for large clusters)
firewall-cmd --permanent --add-protocol=ipip # Calico IP-in-IP encapsulation
firewall-cmd --permanent --zone=trusted --add-source=10.4.0.0/24 # Node Network
firewall-cmd --permanent --zone=trusted --add-source=192.168.0.0/16 # Calico Pod CIDR
firewall-cmd --permanent --zone=trusted --add-source=10.96.0.0/12 # Service CIDR
firewall-cmd --permanent --zone=trusted --add-interface=cali+
firewall-cmd --permanent --zone=trusted --add-interface=tunl0
firewall-cmd --permanent --zone=trusted --add-interface=vxlan.calico
firewall-cmd --reload
Executable
+350
View File
@@ -0,0 +1,350 @@
#!/usr/bin/env bash
# Copyright The Helm Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# The install script is based off of the MIT-licensed script from glide,
# the package manager for Go: https://github.com/Masterminds/glide.sh/blob/master/get
: ${BINARY_NAME:="helm"}
: ${USE_SUDO:="true"}
: ${DEBUG:="false"}
: ${VERIFY_CHECKSUM:="true"}
: ${VERIFY_SIGNATURES:="false"}
: ${HELM_INSTALL_DIR:="/usr/local/bin"}
: ${GPG_PUBRING:="pubring.kbx"}
HAS_CURL="$(type "curl" &> /dev/null && echo true || echo false)"
HAS_WGET="$(type "wget" &> /dev/null && echo true || echo false)"
HAS_OPENSSL="$(type "openssl" &> /dev/null && echo true || echo false)"
HAS_GPG="$(type "gpg" &> /dev/null && echo true || echo false)"
HAS_GIT="$(type "git" &> /dev/null && echo true || echo false)"
HAS_TAR="$(type "tar" &> /dev/null && echo true || echo false)"
# initArch discovers the architecture for this system.
initArch() {
ARCH=$(uname -m)
case $ARCH in
armv5*) ARCH="armv5";;
armv6*) ARCH="armv6";;
armv7*) ARCH="arm";;
aarch64) ARCH="arm64";;
x86) ARCH="386";;
x86_64) ARCH="amd64";;
i686) ARCH="386";;
i386) ARCH="386";;
esac
}
# initOS discovers the operating system for this system.
initOS() {
OS=$(echo `uname`|tr '[:upper:]' '[:lower:]')
case "$OS" in
# Minimalist GNU for Windows
mingw*|cygwin*) OS='windows';;
esac
}
# runs the given command as root (detects if we are root already)
runAsRoot() {
if [ $EUID -ne 0 -a "$USE_SUDO" = "true" ]; then
sudo "${@}"
else
"${@}"
fi
}
# verifySupported checks that the os/arch combination is supported for
# binary builds, as well whether or not necessary tools are present.
verifySupported() {
local supported="darwin-amd64\ndarwin-arm64\nlinux-386\nlinux-amd64\nlinux-arm\nlinux-arm64\nlinux-loong64\nlinux-ppc64le\nlinux-s390x\nlinux-riscv64\nwindows-amd64\nwindows-arm64"
if ! echo "${supported}" | grep -q "${OS}-${ARCH}"; then
echo "No prebuilt binary for ${OS}-${ARCH}."
echo "To build from source, go to https://github.com/helm/helm"
exit 1
fi
if [ "${HAS_CURL}" != "true" ] && [ "${HAS_WGET}" != "true" ]; then
echo "Either curl or wget is required"
exit 1
fi
if [ "${VERIFY_CHECKSUM}" == "true" ] && [ "${HAS_OPENSSL}" != "true" ]; then
echo "In order to verify checksum, openssl must first be installed."
echo "Please install openssl or set VERIFY_CHECKSUM=false in your environment."
exit 1
fi
if [ "${VERIFY_SIGNATURES}" == "true" ]; then
if [ "${HAS_GPG}" != "true" ]; then
echo "In order to verify signatures, gpg must first be installed."
echo "Please install gpg or set VERIFY_SIGNATURES=false in your environment."
exit 1
fi
if [ "${OS}" != "linux" ]; then
echo "Signature verification is currently only supported on Linux."
echo "Please set VERIFY_SIGNATURES=false or verify the signatures manually."
exit 1
fi
fi
if [ "${HAS_GIT}" != "true" ]; then
echo "[WARNING] Could not find git. It is required for plugin installation."
fi
if [ "${HAS_TAR}" != "true" ]; then
echo "[ERROR] Could not find tar. It is required to extract the helm binary archive."
exit 1
fi
}
# checkDesiredVersion checks if the desired version is available.
checkDesiredVersion() {
if [ "x$DESIRED_VERSION" == "x" ]; then
# Get tag from release URL
# Cache behavior is provider-specific, so this mitigation is best effort.
# The current CDN does not revalidate on the request no-cache directive,
# so use a unique query while retaining no-cache for compliant intermediaries.
local latest_release_url="https://get.helm.sh/helm4-latest-version?ts=$(date +%s)"
local latest_release_response=""
if [ "${HAS_CURL}" == "true" ]; then
latest_release_response=$( curl -L --silent --show-error --fail --header "Cache-Control: no-cache" "$latest_release_url" 2>&1 || true )
elif [ "${HAS_WGET}" == "true" ]; then
latest_release_response=$( wget "$latest_release_url" --header="Cache-Control: no-cache" -q -O - 2>&1 || true )
fi
TAG=$( echo "$latest_release_response" | grep '^v[0-9]' )
if [ "x$TAG" == "x" ]; then
printf "Could not retrieve the latest release tag information from %s: %s\n" "${latest_release_url}" "${latest_release_response}"
exit 1
fi
else
TAG=$DESIRED_VERSION
fi
}
# checkHelmInstalledVersion checks which version of helm is installed and
# if it needs to be changed.
checkHelmInstalledVersion() {
if [[ -f "${HELM_INSTALL_DIR}/${BINARY_NAME}" ]]; then
local version=$("${HELM_INSTALL_DIR}/${BINARY_NAME}" version --template="{{ .Version }}")
if [[ "$version" == "$TAG" ]]; then
echo "Helm ${version} is already ${DESIRED_VERSION:-latest}"
return 0
else
echo "Helm ${TAG} is available. Changing from version ${version}."
return 1
fi
else
return 1
fi
}
# downloadFile downloads the latest binary package and also the checksum
# for that binary.
downloadFile() {
HELM_DIST="helm-$TAG-$OS-$ARCH.tar.gz"
DOWNLOAD_URL="https://get.helm.sh/$HELM_DIST"
CHECKSUM_URL="$DOWNLOAD_URL.sha256"
HELM_TMP_ROOT="$(mktemp -dt helm-installer-XXXXXX)"
HELM_TMP_FILE="$HELM_TMP_ROOT/$HELM_DIST"
HELM_SUM_FILE="$HELM_TMP_ROOT/$HELM_DIST.sha256"
echo "Downloading $DOWNLOAD_URL"
if [ "${HAS_CURL}" == "true" ]; then
curl -SsL "$CHECKSUM_URL" -o "$HELM_SUM_FILE"
curl -SsL "$DOWNLOAD_URL" -o "$HELM_TMP_FILE"
elif [ "${HAS_WGET}" == "true" ]; then
wget -q -O "$HELM_SUM_FILE" "$CHECKSUM_URL"
wget -q -O "$HELM_TMP_FILE" "$DOWNLOAD_URL"
fi
}
# verifyFile verifies the SHA256 checksum of the binary package
# and the GPG signatures for both the package and checksum file
# (depending on settings in environment).
verifyFile() {
if [ "${VERIFY_CHECKSUM}" == "true" ]; then
verifyChecksum
fi
if [ "${VERIFY_SIGNATURES}" == "true" ]; then
verifySignatures
fi
}
# installFile installs the Helm binary.
installFile() {
HELM_TMP="$HELM_TMP_ROOT/$BINARY_NAME"
mkdir -p "$HELM_TMP"
tar xf "$HELM_TMP_FILE" -C "$HELM_TMP"
HELM_TMP_BIN="$HELM_TMP/$OS-$ARCH/helm"
echo "Preparing to install $BINARY_NAME into ${HELM_INSTALL_DIR}"
runAsRoot cp "$HELM_TMP_BIN" "$HELM_INSTALL_DIR/$BINARY_NAME"
echo "$BINARY_NAME installed into $HELM_INSTALL_DIR/$BINARY_NAME"
}
# verifyChecksum verifies the SHA256 checksum of the binary package.
verifyChecksum() {
printf "Verifying checksum... "
local sum=$(openssl sha1 -sha256 ${HELM_TMP_FILE} | awk '{print $2}')
local expected_sum=$(cat ${HELM_SUM_FILE})
if [ "$sum" != "$expected_sum" ]; then
echo "SHA sum of ${HELM_TMP_FILE} does not match. Aborting."
exit 1
fi
echo "Done."
}
# verifySignatures obtains the latest KEYS file from GitHub main branch
# as well as the signature .asc files from the specific GitHub release,
# then verifies that the release artifacts were signed by a maintainer's key.
verifySignatures() {
printf "Verifying signatures... "
local keys_filename="KEYS"
local github_keys_url="https://raw.githubusercontent.com/helm/helm/main/${keys_filename}"
if [ "${HAS_CURL}" == "true" ]; then
curl -SsL "${github_keys_url}" -o "${HELM_TMP_ROOT}/${keys_filename}"
elif [ "${HAS_WGET}" == "true" ]; then
wget -q -O "${HELM_TMP_ROOT}/${keys_filename}" "${github_keys_url}"
fi
local gpg_keyring="${HELM_TMP_ROOT}/keyring.gpg"
local gpg_homedir="${HELM_TMP_ROOT}/gnupg"
mkdir -p -m 0700 "${gpg_homedir}"
local gpg_stderr_device="/dev/null"
if [ "${DEBUG}" == "true" ]; then
gpg_stderr_device="/dev/stderr"
fi
gpg --batch --quiet --homedir="${gpg_homedir}" --import "${HELM_TMP_ROOT}/${keys_filename}" 2> "${gpg_stderr_device}"
gpg --batch --no-default-keyring --keyring "${gpg_homedir}/${GPG_PUBRING}" --export > "${gpg_keyring}"
local github_release_url="https://github.com/helm/helm/releases/download/${TAG}"
if [ "${HAS_CURL}" == "true" ]; then
curl -SsL "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" -o "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc"
curl -SsL "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" -o "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc"
elif [ "${HAS_WGET}" == "true" ]; then
wget -q -O "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc"
wget -q -O "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc"
fi
local error_text="If you think this might be a potential security issue,"
error_text="${error_text}\nplease see here: https://github.com/helm/community/blob/master/SECURITY.md"
local num_goodlines_sha=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)')
if [[ ${num_goodlines_sha} -lt 2 ]]; then
echo "Unable to verify the signature of helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256!"
echo -e "${error_text}"
exit 1
fi
local num_goodlines_tar=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)')
if [[ ${num_goodlines_tar} -lt 2 ]]; then
echo "Unable to verify the signature of helm-${TAG}-${OS}-${ARCH}.tar.gz!"
echo -e "${error_text}"
exit 1
fi
echo "Done."
}
# fail_trap is executed if an error occurs.
fail_trap() {
result=$?
if [ "$result" != "0" ]; then
if [[ -n "$INPUT_ARGUMENTS" ]]; then
echo "Failed to install $BINARY_NAME with the arguments provided: $INPUT_ARGUMENTS"
help
else
echo "Failed to install $BINARY_NAME"
fi
echo -e "\tFor support, go to https://github.com/helm/helm."
fi
cleanup
exit $result
}
# testVersion tests the installed client to make sure it is working.
testVersion() {
set +e
HELM="$(command -v $BINARY_NAME)"
if [ "$?" = "1" ]; then
echo "$BINARY_NAME not found. Is $HELM_INSTALL_DIR on your "'$PATH?'
exit 1
fi
set -e
}
# help provides possible cli installation arguments
help () {
echo "Accepted cli arguments are:"
echo -e "\t[--help|-h ] ->> prints this help"
echo -e "\t[--version|-v <desired_version>] . When not defined it fetches the latest release tag from the Helm CDN"
echo -e "\te.g. --version v4.0.0 or -v canary"
echo -e "\t[--no-sudo] ->> install without sudo"
}
# cleanup temporary files to avoid https://github.com/helm/helm/issues/2977
cleanup() {
if [[ -d "${HELM_TMP_ROOT:-}" ]]; then
rm -rf "$HELM_TMP_ROOT"
fi
}
# Execution
#Stop execution on any error
trap "fail_trap" EXIT
set -e
# Set debug if desired
if [ "${DEBUG}" == "true" ]; then
set -x
fi
# Parsing input arguments (if any)
export INPUT_ARGUMENTS="${@}"
set -u
while [[ $# -gt 0 ]]; do
case $1 in
'--version'|-v)
shift
if [[ $# -ne 0 ]]; then
export DESIRED_VERSION="${1}"
if [[ "$1" != "v"* ]]; then
echo "Expected version arg ('${DESIRED_VERSION}') to begin with 'v', fixing..."
export DESIRED_VERSION="v${1}"
fi
else
echo -e "Please provide the desired version. e.g. --version v4.0.0 or -v canary"
exit 0
fi
;;
'--no-sudo')
USE_SUDO="false"
;;
'--help'|-h)
help
exit 0
;;
*) exit 1
;;
esac
shift
done
set +u
initArch
initOS
verifySupported
checkDesiredVersion
if ! checkHelmInstalledVersion; then
downloadFile
verifyFile
installFile
fi
testVersion
cleanup
+1
View File
@@ -0,0 +1 @@
no AI used here. Pretty much just a copy+paste of my Gitea deployment on Openshift. Worth noting - I actually started out with a helm chart deployment, but ran into issues with pods not spinning up, so I went back to basics and did it fully manually and worked perfectly.
+19
View File
@@ -0,0 +1,19 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
annotations:
name: letsencrypt
namespace: gitea
spec:
commonName: 'gitea.k8s.lab.cudanet.org'
dnsNames:
- 'gitea.k8s.lab.cudanet.org'
duration: 2160h0m0s
issuerRef:
kind: ClusterIssuer
name: letsencrypt
renewBefore: 360h0m0s
secretName: letsencrypt
usages:
- server auth
- client auth
+70
View File
@@ -0,0 +1,70 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
labels:
app: gitea
app.kubernetes.io/component: gitea
app.kubernetes.io/instance: gitea
name: gitea
namespace: gitea
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
deployment: gitea
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
annotations:
creationTimestamp: null
labels:
deployment: gitea
spec:
containers:
- env:
- name: GITEA__database__DB_TYPE
value: mysql
- name: GITEA__database__HOST
value: mariadb
- name: GITEA__database__NAME
value: gitea
- name: GITEA__database__USER
value: gitea
- name: GITEA__database__PASSWD
value: gitea
image: docker.gitea.com/gitea@sha256:3a54ec4b271f0479eb1f40624cbf90f2245306aab8533dd14bb5f49f4c580ccf
imagePullPolicy: IfNotPresent
name: gitea
ports:
- containerPort: 2222
protocol: TCP
- containerPort: 3000
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /etc/gitea
name: gitea-config
- mountPath: /var/lib/gitea
name: gitea-data
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: gitea-config
persistentVolumeClaim:
claimName: gitea-config
- name: gitea-data
persistentVolumeClaim:
claimName: gitea-data
+33
View File
@@ -0,0 +1,33 @@
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
name: gitea-config
namespace: gitea
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 100Gi
storageClassName: nfs
volumeMode: Filesystem
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
finalizers:
- kubernetes.io/pvc-protection
name: gitea-data
namespace: gitea
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 100Gi
storageClassName: nfs
volumeMode: Filesystem
---
+28
View File
@@ -0,0 +1,28 @@
apiVersion: v1
kind: Service
metadata:
labels:
app: gitea
app.kubernetes.io/component: gitea
app.kubernetes.io/instance: gitea
name: gitea
namespace: gitea
spec:
clusterIP:
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: web
port: 3000
protocol: TCP
targetPort: 3000
- name: ssh
port: 2222
protocol: TCP
targetPort: 2222
selector:
deployment: gitea
sessionAffinity: None
type: ClusterIP
+24
View File
@@ -0,0 +1,24 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gitea-ingress
namespace: gitea
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
spec:
ingressClassName: traefik
tls:
- hosts:
- gitea.k8s.lab.cudanet.org
secretName: letsencrypt
rules:
- host: gitea.k8s.lab.cudanet.org
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: gitea
port:
number: 3000
+14
View File
@@ -0,0 +1,14 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: gitea-web
namespace: gitea
spec:
entryPoints:
- websecure
routes:
- match: Host(`gitea.k8s.lab.cudanet.org`)
kind: Rule
services:
- name: gitea
port: 3000
+60
View File
@@ -0,0 +1,60 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
labels:
app: mariadb
app.kubernetes.io/component: mariadb
app.kubernetes.io/instance: mariadb
name: mariadb
namespace: gitea
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
deployment: mariadb
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
annotations:
labels:
deployment: mariadb
spec:
containers:
- env:
- name: MYSQL_ROOT_PASSWORD
value: gitea
- name: MYSQL_USER
value: gitea
- name: MYSQL_PASSWORD
value: gitea
- name: MYSQL_DATABASE
value: gitea
image: docker.io/library/mariadb@sha256:659a15e38f4ccb2bfa2c7cf824a8a5955fdc5f63cfd01537bc25c9e0ff716605
imagePullPolicy: IfNotPresent
name: mariadb
ports:
- containerPort: 3306
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/lib/mysql
name: mariadb
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: mariadb
persistentVolumeClaim:
claimName: mariadb
+15
View File
@@ -0,0 +1,15 @@
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
name: mariadb
namespace: gitea
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 100Gi
storageClassName: nfs
volumeMode: Filesystem
+26
View File
@@ -0,0 +1,26 @@
---
apiVersion: v1
kind: Service
metadata:
annotations:
labels:
app: mariadb
app.kubernetes.io/component: mariadb
app.kubernetes.io/instance: mariadb
name: mariadb
namespace: gitea
spec:
clusterIP:
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: 3306-tcp
port: 3306
protocol: TCP
targetPort: 3306
selector:
deployment: mariadb
sessionAffinity: None
type: ClusterIP
+8
View File
@@ -0,0 +1,8 @@
---
apiVersion: v1
kind: Namespace
metadata:
annotations:
labels:
kubernetes.io/metadata.name: gitea
name: gitea
+3
View File
@@ -0,0 +1,3 @@
no AI used in the deployment of headlamp, just a straightforward install from the instructions here https://headlamp.dev/docs/latest/installation/in-cluster/
However, I did ask AI how to generate a non-expiring token since I didn't remember the exact command to do so.
+16
View File
@@ -0,0 +1,16 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headlamp
namespace: headlamp
spec:
entryPoints:
- websecure
routes:
- match: Host(`headlamp.k8s.lab.cudanet.org`)
kind: Rule
services:
- name: headlamp
port: 80
tls:
certResolver: letsencrypt
+27
View File
@@ -0,0 +1,27 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: headlamp-admin
namespace: headlamp
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: headlamp-admin-binding
subjects:
- kind: ServiceAccount
name: headlamp-admin
namespace: headlamp
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: Secret
metadata:
name: headlamp-admin-token
namespace: headlamp
annotations:
kubernetes.io/service-account.name: headlamp-admin
type: kubernetes.io/service-account-token
+1
View File
@@ -0,0 +1 @@
eyJhbGciOiJSUzI1NiIsImtpZCI6InJTeEp1ZTlwbzZnUkduNk5hN2Fhc0hMTHQtRTM1RlZlcGJZX2J4OS1GSFkifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJoZWFkbGFtcCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJoZWFkbGFtcC1hZG1pbi10b2tlbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJoZWFkbGFtcC1hZG1pbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjgyMmU4ODUxLTE3OTQtNDhkZi1hYjA4LTJiY2FhMDQ0YzgyYSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpoZWFkbGFtcDpoZWFkbGFtcC1hZG1pbiJ9.N7ybibaIl2_bljbsKcR-JiVCpdS15MgwurJqg9QTNchPoVYsncYFbTh4AbASLh97gbE5rYqsdXE7BnoOA70Zn_DZ9KcKI90NzFykDBUPZZaFv1rO5pIRGCdx5gGO5UXjFz3wCYhFTacEGNE9DVFrvBmeNlp8WI7xbHRM2SPG7BDFWwcxWeTXaVFoH6v3P9RRJWXec07JJEq51Un5jjmWV_gFh07pQAkUOwSYNX6ZQG6v2pRDEEAAu0cVmJI3kgvCeQBARXq7XKekGNIt0dQ6MR5B_4IronDDve3AbGLPB7cClKi4oTPD3GJT8cetAHhztIIQp0MnpW-2gNCGnTUmNg
+1
View File
@@ -0,0 +1 @@
I mostly referred to my personal notes for the actual process of bootstrapping the cluster with kubeadm. However, I did ask AI to generate an example kubeadm-config.yaml since I didn't seem to have an old copy to reference in my files.
+30
View File
@@ -0,0 +1,30 @@
apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: "10.4.0.10"
bindPort: 6443
nodeRegistration:
name: "control-plane.k8s.lab.cudanet.org"
criSocket: "unix:///var/run/crio/crio.sock"
imagePullPolicy: "IfNotPresent"
taints:
- effect: "NoSchedule"
key: "node-role.kubernetes.io/control-plane"
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: "v1.37.0"
clusterName: "kubernetes"
controlPlaneEndpoint: "control-plane.k8s.lab.cudanet.org:6443"
apiServer:
certSANs:
- "control-plane.k8s.lab.cudanet.org"
- "10.4.0.10"
networking:
dnsDomain: "cluster.local"
serviceSubnet: "10.96.0.0/12"
podSubnet: "192.168.0.0/16"
---
apiVersion: kubeletconfiguration.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: "systemd"
+1
View File
@@ -0,0 +1 @@
no AI here, just a quick google "helm install metallb". I've been spoiled with it just being an operator on Openshift for so long, I had to look it up. Creating the ipaddresspool and l2advert was basically just a copy+paste from what I use on OCP.
+17
View File
@@ -0,0 +1,17 @@
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default-pool
namespace: metallb-system
spec:
addresses:
- 10.4.0.200-10.4.0.220
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: l2-adv
namespace: metallb-system
spec:
ipAddressPools:
- default-pool
Submodule
+1
Submodule nginx added at 745619cfc1
+3
View File
@@ -0,0 +1,3 @@
I did rely on AI to kludge my way through this process, because I've never had to do it before. Thus far my experience managing RBAC on kuberneties has been leveraging OIDC with some form of SSO, like LDAP (Active Directory/FreeIPA).
This was a learning experience for me.
+12
View File
@@ -0,0 +1,12 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: rcuda-cluster-admin-binding
subjects:
- kind: User
name: rcuda # Must match the CN from the certificate
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
+18
View File
@@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC9TCCAd2gAwIBAgIQKfkUgQPfbuziunLbS0Y2BTANBgkqhkiG9w0BAQsFADAV
MRMwEQYDVQQDEwprdWJlcm5ldGVzMB4XDTI2MTAzMDE2MTA1N1oXDTI2MTAzMTE2
MTA1N1owEDEOMAwGA1UEAxMFcmN1ZGEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQCTVTfCRu4v4LgHXsFem0KfkoSAxy498g2qCSsgDegDUUYUC7ptXNLG
Y8McyZRlmiCGhfRKygq3zm/3da5w806/ldPZikiUuXIi2brc+2es6ey7tKQUXTtU
/R8NmtyXVIErBwbQeHKXIH65+tJtmWhzvmvbzCIGisaldKnSQDoy3bXPUaawJm0W
wnzsv9YWJ9JIr7RU15N9ngG3RAF+eYgxarJOZHHJK0qmPeSB6Ux9kIGlfSTNndAW
dG0CB81kxV4FnlYQdw+/nBfoluhLAzL+VUzLUeE2ujin3o2Yy6v3Xiqyzg6Sa9y4
1WcjtP78KuFiQOudiZlUS83bjmAcpBzbAgMBAAGjRjBEMBMGA1UdJQQMMAoGCCsG
AQUFBwMCMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUkd2GsW22p+1bykQ+Pqb9
JVefciIwDQYJKoZIhvcNAQELBQADggEBAIf+b5tyZYL9sx+eRVTPf0kMXGDDzG30
eNPhiixChR+kD710OJgNrwfCSTF1/rtelOluVRYK4qs8ktp/ifczBF+AsMT1pW8/
Ov8FVMT/cJC8P2GAR+6nK4pWYc0PyNpAyjkKq3xLnpc+NIucybPNXiFbXwGeAhFz
ICHI529PVqxyMK+bMEs4wA3ankpkarOd3GkjX2tBhrWbAs8wFF52sRCzBHjTgj37
sEUrYi7qEkmw4oJTr7LXw6Ajye/9GaFlhScyytr/WeBo3Mp/TcpkoxyIvGMs49wK
5Q80UrCkZSk3zWApuMeqg/pUW7RcsZY9AQMYfe78ziK1wgLjNudH6Y4=
-----END CERTIFICATE-----
+15
View File
@@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICVTCCAT0CAQAwEDEOMAwGA1UEAwwFcmN1ZGEwggEiMA0GCSqGSIb3DQEBAQUA
A4IBDwAwggEKAoIBAQCTVTfCRu4v4LgHXsFem0KfkoSAxy498g2qCSsgDegDUUYU
C7ptXNLGY8McyZRlmiCGhfRKygq3zm/3da5w806/ldPZikiUuXIi2brc+2es6ey7
tKQUXTtU/R8NmtyXVIErBwbQeHKXIH65+tJtmWhzvmvbzCIGisaldKnSQDoy3bXP
UaawJm0Wwnzsv9YWJ9JIr7RU15N9ngG3RAF+eYgxarJOZHHJK0qmPeSB6Ux9kIGl
fSTNndAWdG0CB81kxV4FnlYQdw+/nBfoluhLAzL+VUzLUeE2ujin3o2Yy6v3Xiqy
zg6Sa9y41WcjtP78KuFiQOudiZlUS83bjmAcpBzbAgMBAAGgADANBgkqhkiG9w0B
AQsFAAOCAQEAhPbV9ue8FWhX+rlW7qT+4qruzYKFSn5OVZ6qMOAJr4vQwJjQhQbT
MWLxh2nBH1Q56iW1lUVU/FjvyGsHsoPEvNKWxYtBeGeICjllpkcDyCtB0UAHhj0X
efFghXM5kzh6YhgjDiKIajx4m7C0GFZBYvyxo8gYfpp+PBgaWsSztp7dzxQdU74k
sGQ69R/4yQY7uVYgHNCB7shN6jT/XUWGBypOtYejP8cdKf0ZecO1PL8DvsS4jVzL
fVNVEvWf0DlaEJdIJEvFwZNxfqf7UdXARCReZBKs5rYPFBsyjiL4y3v43WzTzZKy
ECLNLgDMicf00nTZ2+ob4q8vJ4kK1cqnXg==
-----END CERTIFICATE REQUEST-----
+28
View File
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCTVTfCRu4v4LgH
XsFem0KfkoSAxy498g2qCSsgDegDUUYUC7ptXNLGY8McyZRlmiCGhfRKygq3zm/3
da5w806/ldPZikiUuXIi2brc+2es6ey7tKQUXTtU/R8NmtyXVIErBwbQeHKXIH65
+tJtmWhzvmvbzCIGisaldKnSQDoy3bXPUaawJm0Wwnzsv9YWJ9JIr7RU15N9ngG3
RAF+eYgxarJOZHHJK0qmPeSB6Ux9kIGlfSTNndAWdG0CB81kxV4FnlYQdw+/nBfo
luhLAzL+VUzLUeE2ujin3o2Yy6v3Xiqyzg6Sa9y41WcjtP78KuFiQOudiZlUS83b
jmAcpBzbAgMBAAECggEAGJQN0j4s/BW7/ZbEIXk7Ow2hRy5zO2hG+UfARv+q5erI
Cw4N0rK6gtgfs4y5Ud3NcUOlhliAQzuQGDMsn7EnQPTIu7DC/PSW4tN5xeW23PTF
RmcTPEZ1YG89n/JmvGQfjEMG0v5U93s3SOVb92axMyXgLnG2d2rtSqrUrbuDOfrb
yxtpE0quBULpKuIdHwxOxntXo4aTAYX1lcS85U4bQXNQ1/7IqSgpHd2eqV0eatHE
LEMhZ0Iicot//VXvWx/zDeAX7nwPSAhtzRlMR2LEh5eYj3lHNd2XxrhYBqhtbDqZ
f2GYuxTkvz5QcGLirYkhOrGC7kZ4Lh9VxGBc6lAtmQKBgQDGLa75VAIBjMcUA7cq
JIf26+IdmMIsbhW/kb4unXkMFLvHMDFJiNks6k9WQymbg2vxuCUeB82CRyahtSDv
kUFgyT+LKRnakiYWnvdEtsC85z5CrpCvW6jQPnKvnecbD/2obxuoco8K6X4IaN/K
EOFmrZbTRSC5oVXcV3ZhhTYzZQKBgQC+UcjLCL4WcvFmwso/CQedSxkrtMvjrMRi
7zcJ+WaQBoTbihtCGmpeOCgNKBx90OdyxjutpREB55w5GUvROjVJOQS34IDr7qT0
6XRVzP5xEiV7stPRPZq5TfPMlRh/15Iz3sxFL8U4jaLqVtF7b66RoiwhG5E1MrPq
K5qlMwWrPwKBgQCvpbHdnk2g3gtce+aN3Y78lRj2Lnx7MJ7qCdzMKBovUPkVlGs6
x6XlH09uH1zzTsoPlaygLz5AZ5uf24/zhYSyqew+BRG7HanQhtiV+HxfcX1HUL1A
DzdSSucPLB63Z7bk4IVdCRwrCcQA5CLlT4zXmqeBXVWh8ZLOFl8AFDdz2QKBgQCI
3NVxtKrGCAizZlb8t6ijI7NJK+4Hn2Fm6DIDWTe5UQbPveRWSBrAANBEjdjXXZhj
gEzAVdkCLqW4pglQv/Q74OYUuTzc7bPwb8X6Qb2kYHFWIEaUzSFsKrOtJncE0GhS
JuFsy6qfPbOvo5lnk+vMzPvBH0rwH7MkLhE6xZNJDwKBgBTMnQJxWCKYOGd0RKVv
6MisPvd/nrVvaDaoozCXrWQ+SHa6qZDIHIEQOkpRi5x13A3UgjRfrNWTqinTeKAp
Ue7G+mdfmd+HUVYS5/qJPnnoPsswJ9G9xbGUeo06U5ivs4qj4Rl5OU5nEgwKHpuq
GBb9eonSCVDPpqhJL/50jZ+e
-----END PRIVATE KEY-----
+247
View File
@@ -0,0 +1,247 @@
#!/bin/bash
set -e
echo "# Running [control-plane.k8s.lab.cudanet.org] host initial configuration"
exit_and_cancel_build() {
echo 'Host [control-plane.k8s.lab.cudanet.org] initial configuration failed'
SSL_CA_CERT=$(mktemp)
cat << EOF > $SSL_CA_CERT
-----BEGIN CERTIFICATE-----
MIIG6TCCBNGgAwIBAgIUIacbh/WYmORFpiddBg25g/W4jlQwDQYJKoZIhvcNAQEL
BQAwgYExCzAJBgNVBAYTAlVTMRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTEQMA4G
A1UEBwwHUmFsZWlnaDEQMA4GA1UECgwHS2F0ZWxsbzEUMBIGA1UECwwLU29tZU9y
Z1VuaXQxHzAdBgNVBAMMFnNhdGwwMS5sYWIuY3VkYW5ldC5vcmcwHhcNMjYwOTEx
MTc1NTA1WhcNMzgwMTE3MTc1NTA1WjCBgTELMAkGA1UEBhMCVVMxFzAVBgNVBAgM
Dk5vcnRoIENhcm9saW5hMRAwDgYDVQQHDAdSYWxlaWdoMRAwDgYDVQQKDAdLYXRl
bGxvMRQwEgYDVQQLDAtTb21lT3JnVW5pdDEfMB0GA1UEAwwWc2F0bDAxLmxhYi5j
dWRhbmV0Lm9yZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAN6uVBDW
Qp941uKRabwV2vtuGftmply2vA4cFbw0k1vAosRPE130ULNkhm8wK7qwu+bqNKi6
2okdfIBAm+u7Tw0NYufcMDyEjngqMCG54w3OGbLW4ZQIefIliKw/kdUhxvKvzxNT
DP7kK+uwnunW6l79G8azAtDddhNa0wafkMHpQYeU/Y650oto+c3qjETTIC3M2QVr
N7D5niWAmrLvHyR/2S/W2Oa2929PmENMuBUsEgcoYthagDjse7G2hp8Gll4cCVh4
LysBzTUFUBC5NRx7eqf0iCycexXcAZunHQfNCwHJNXdUFc61pBeFmTtslxTMdNmV
FZ9SV5++ESHK75RYlhnfHGSiByUtstDXGT1vCUkipmzI4p3zVRPj5whlg0i15hdz
R58q9uftSYOwr5od3UIXJQM2fNlip7rIy85av2le3TkwmjObQqP7nNmacWarwQfs
dTVcslv+CI7vXtdWGqcRMo0db+QQN8tSGOfSTGDqt4lmwk7ESg48UocOAhoOEzIY
pEQnBLtSxEDBsFEu4vwNlq5DanSD3vuxwyDC6T8AdxTQvVclM+x+CsANaVzrLM6W
e7KJOYfe7J/dM28OWOTdLSSJ+L9gYxtdXme9uYLmQptce7KnuwoHozRY/aP0hFN/
2hMNEYlPFkUGvvb+hKzziagh+Rky9IP8/dWjAgMBAAGjggFVMIIBUTAMBgNVHRME
BTADAQH/MAsGA1UdDwQEAwIBpjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH
AwIwEQYJYIZIAYb4QgEBBAQDAgJEMDUGCWCGSAGG+EIBDQQoFiZLYXRlbGxvIFNT
TCBUb29sIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUepliLqnv9s1n
TKkZeHtZA8eNPdgwgasGA1UdIwSBozCBoKGBh6SBhDCBgTELMAkGA1UEBhMCVVMx
FzAVBgNVBAgMDk5vcnRoIENhcm9saW5hMRAwDgYDVQQHDAdSYWxlaWdoMRAwDgYD
VQQKDAdLYXRlbGxvMRQwEgYDVQQLDAtTb21lT3JnVW5pdDEfMB0GA1UEAwwWc2F0
bDAxLmxhYi5jdWRhbmV0Lm9yZ4IUIacbh/WYmORFpiddBg25g/W4jlQwDQYJKoZI
hvcNAQELBQADggIBAGeB30OcUUdVO5gTWnNorYHhkhxuWri1ThCQqzBlaUKFQ35I
120CcZ2rc22Q/kQqLHfB3bvGEe379Bw/6kRKOZVf7cd34yqqORSQxWqkPSQIjKfw
K5kXRn2aCQSh/Ohfoowz0ow5HngTzShiL+KlPuix6Zuz2R+1uZwpDZifUiUVydnx
Ru0XiZBFX+u4zUAPJHYC94t14Omvpo8J1qbfC9Wc9Anlx4I7PXqJ8rygSrxU8him
QhExutff7TC4yA2nPVLvGJV96eAl9nQdiux8EKhvJ4y66/e4IqFNVYtiyCpH2epv
rLRgWCmpBDONHL2LM82HJZXKtU8rwRUCsKnt2pjRR2BTEkCH5GNQasLI76TEorV3
Z+d8LWBHZgmsbR2BcCv7eSd29NAMoRalCx1emEJm/yizzXm3ADlH9PWR9bwuwMxx
IRcB1EsKXpWlzaJY3TfJ8p1cUqcx3Dm8majSb9nkTkbH5XuVf2hipz1URpYlcDjk
DUcFWbs+2BqLU9Gg4mZJMHc6XDsduv+sjaA5D8w5bYZfgqLA39/LPKPQCQ2vcYIm
CviivD2WpDXdkp2BFNV3lX/H6Vnlc2Mc6utUxMem2Ip7bBISIGayZKHyjOsAU+hh
T/giRQe8jtPFNh+pnEWBo83XMalqn0V5C7m/Jwb28bc7IPtPPlRcfYsnhY5y
-----END CERTIFICATE-----
EOF
if [ -x /usr/bin/curl ]; then
/usr/bin/curl -o /dev/null -H 'Content-Type: text/plain' --fail --data 'Host initial configuration failed, please see the registration log for more details.' --noproxy \* --cacert $SSL_CA_CERT --silent 'https://satl01.lab.cudanet.org/unattended/failed?token=10fd076d-92f5-4f80-83ad-3cb330ac4069'
elif [ -x /usr/bin/wget ]; then
/usr/bin/wget -q -O /dev/null --method POST --header 'Content-Type: text/plain' --body-data='Host initial configuration failed, please see the registration log for more details.' --no-proxy --ca-certificate $SSL_CA_CERT 'https://satl01.lab.cudanet.org/unattended/failed?token=10fd076d-92f5-4f80-83ad-3cb330ac4069'
else
wget -q -O /dev/null --header 'Content-Type: text/plain' 'https://satl01.lab.cudanet.org/unattended/failed?token=10fd076d-92f5-4f80-83ad-3cb330ac4069'
fi
FINAL_STATUS=$?
if [ -x "$(command -v subscription-manager)" ] ; then
subscription-manager facts --update
SUB_MAN_STATUS=$?
if [ $FINAL_STATUS -eq 0 ]; then
FINAL_STATUS=$SUB_MAN_STATUS
fi
fi
(exit $FINAL_STATUS);
exit 1
}
set +e
trap 'exit_and_cancel_build' ERR
# Select package manager for the OS (sets the $PKG_MANAGER* variables)
if [ -z "$PKG_MANAGER" ]; then
if [ -f /etc/os-release ] ; then
. /etc/os-release
fi
if [ "${NAME%.*}" = 'FreeBSD' ]; then
PKG_MANAGER='pkg'
PKG_MANAGER_INSTALL="${PKG_MANAGER} install -y"
PKG_MANAGER_REMOVE="${PKG_MANAGER} delete -y"
PKG_MANAGER_UPGRADE="${PKG_MANAGER} install -y"
elif [ -f /etc/fedora-release -o -f /etc/redhat-release -o -f /etc/amazon-linux-release -o -f /etc/system-release ]; then
PKG_MANAGER='dnf'
if [ -f /etc/redhat-release -a "${VERSION_ID%.*}" -le 7 ]; then
PKG_MANAGER='yum'
elif [ -f /etc/system-release ]; then
PKG_MANAGER='yum'
fi
PKG_MANAGER_INSTALL="${PKG_MANAGER} install -y"
PKG_MANAGER_REMOVE="${PKG_MANAGER} remove -y"
PKG_MANAGER_UPGRADE="${PKG_MANAGER} upgrade -y"
elif [ -f /etc/debian_version ]; then
PKG_MANAGER='apt-get'
PKG_MANAGER_INSTALL="${PKG_MANAGER} -o 'Dpkg::Options::=--force-confdef' -o 'Dpkg::Options::=--force-confold' install -y"
PKG_MANAGER_REMOVE="${PKG_MANAGER} -o 'Dpkg::Options::=--force-confdef' -o 'Dpkg::Options::=--force-confold' remove -y"
PKG_MANAGER_UPGRADE="${PKG_MANAGER} -o 'Dpkg::Options::=--force-confdef' -o 'Dpkg::Options::=--force-confold' -o APT::Get::Upgrade-Allow-New='true' upgrade -y"
elif [ -f /etc/arch-release ]; then
PKG_MANAGER='pacman'
PKG_MANAGER_INSTALL="${PKG_MANAGER} --noconfirm -S"
PKG_MANAGER_REMOVE="${PKG_MANAGER} --noconfirm -R"
PKG_MANAGER_UPGRADE="${PKG_MANAGER} --noconfirm -S"
elif [ x$ID = xopensuse-tumbleweed -o x$ID = xsles ]; then
PKG_MANAGER='zypper'
PKG_MANAGER_INSTALL="${PKG_MANAGER} --non-interactive install --auto-agree-with-licenses"
PKG_MANAGER_REMOVE="${PKG_MANAGER} --non-interactive remove"
PKG_MANAGER_UPGRADE="${PKG_MANAGER} --non-interactive update"
fi
fi
user_exists=false
getent passwd root >/dev/null 2>&1 && user_exists=true
if $user_exists; then
mkdir -p ~root/.ssh
cat << EOF >> ~root/.ssh/authorized_keys
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHN+jdbQeYICJHV6iVLv/dj+oqeAapadgAUM8y7ZRRvS foreman-proxy@satl01.lab.cudanet.org
EOF
chmod 0700 ~root/.ssh
chmod 0600 ~root/.ssh/authorized_keys
chown -R root: ~root/.ssh
# Restore SELinux context with restorecon, if it's available:
command -v restorecon && restorecon -RvF ~root/.ssh || true
else
echo 'The remote_execution_ssh_user does not exist and remote_execution_create_user is not set to true. remote_execution_ssh_keys snippet will not install keys'
fi
echo '#'
echo '# Installing Insights client'
echo '#'
yum install -y insights-client
insights-client --register < /dev/null
if command -v subscription-manager &>/dev/null; then
echo "Refreshing subscription data"
subscription-manager refresh
fi
# Call home to exit build mode
trap - ERR
SSL_CA_CERT=$(mktemp)
cat << EOF > $SSL_CA_CERT
-----BEGIN CERTIFICATE-----
MIIG6TCCBNGgAwIBAgIUIacbh/WYmORFpiddBg25g/W4jlQwDQYJKoZIhvcNAQEL
BQAwgYExCzAJBgNVBAYTAlVTMRcwFQYDVQQIDA5Ob3J0aCBDYXJvbGluYTEQMA4G
A1UEBwwHUmFsZWlnaDEQMA4GA1UECgwHS2F0ZWxsbzEUMBIGA1UECwwLU29tZU9y
Z1VuaXQxHzAdBgNVBAMMFnNhdGwwMS5sYWIuY3VkYW5ldC5vcmcwHhcNMjYwOTEx
MTc1NTA1WhcNMzgwMTE3MTc1NTA1WjCBgTELMAkGA1UEBhMCVVMxFzAVBgNVBAgM
Dk5vcnRoIENhcm9saW5hMRAwDgYDVQQHDAdSYWxlaWdoMRAwDgYDVQQKDAdLYXRl
bGxvMRQwEgYDVQQLDAtTb21lT3JnVW5pdDEfMB0GA1UEAwwWc2F0bDAxLmxhYi5j
dWRhbmV0Lm9yZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAN6uVBDW
Qp941uKRabwV2vtuGftmply2vA4cFbw0k1vAosRPE130ULNkhm8wK7qwu+bqNKi6
2okdfIBAm+u7Tw0NYufcMDyEjngqMCG54w3OGbLW4ZQIefIliKw/kdUhxvKvzxNT
DP7kK+uwnunW6l79G8azAtDddhNa0wafkMHpQYeU/Y650oto+c3qjETTIC3M2QVr
N7D5niWAmrLvHyR/2S/W2Oa2929PmENMuBUsEgcoYthagDjse7G2hp8Gll4cCVh4
LysBzTUFUBC5NRx7eqf0iCycexXcAZunHQfNCwHJNXdUFc61pBeFmTtslxTMdNmV
FZ9SV5++ESHK75RYlhnfHGSiByUtstDXGT1vCUkipmzI4p3zVRPj5whlg0i15hdz
R58q9uftSYOwr5od3UIXJQM2fNlip7rIy85av2le3TkwmjObQqP7nNmacWarwQfs
dTVcslv+CI7vXtdWGqcRMo0db+QQN8tSGOfSTGDqt4lmwk7ESg48UocOAhoOEzIY
pEQnBLtSxEDBsFEu4vwNlq5DanSD3vuxwyDC6T8AdxTQvVclM+x+CsANaVzrLM6W
e7KJOYfe7J/dM28OWOTdLSSJ+L9gYxtdXme9uYLmQptce7KnuwoHozRY/aP0hFN/
2hMNEYlPFkUGvvb+hKzziagh+Rky9IP8/dWjAgMBAAGjggFVMIIBUTAMBgNVHRME
BTADAQH/MAsGA1UdDwQEAwIBpjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH
AwIwEQYJYIZIAYb4QgEBBAQDAgJEMDUGCWCGSAGG+EIBDQQoFiZLYXRlbGxvIFNT
TCBUb29sIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUepliLqnv9s1n
TKkZeHtZA8eNPdgwgasGA1UdIwSBozCBoKGBh6SBhDCBgTELMAkGA1UEBhMCVVMx
FzAVBgNVBAgMDk5vcnRoIENhcm9saW5hMRAwDgYDVQQHDAdSYWxlaWdoMRAwDgYD
VQQKDAdLYXRlbGxvMRQwEgYDVQQLDAtTb21lT3JnVW5pdDEfMB0GA1UEAwwWc2F0
bDAxLmxhYi5jdWRhbmV0Lm9yZ4IUIacbh/WYmORFpiddBg25g/W4jlQwDQYJKoZI
hvcNAQELBQADggIBAGeB30OcUUdVO5gTWnNorYHhkhxuWri1ThCQqzBlaUKFQ35I
120CcZ2rc22Q/kQqLHfB3bvGEe379Bw/6kRKOZVf7cd34yqqORSQxWqkPSQIjKfw
K5kXRn2aCQSh/Ohfoowz0ow5HngTzShiL+KlPuix6Zuz2R+1uZwpDZifUiUVydnx
Ru0XiZBFX+u4zUAPJHYC94t14Omvpo8J1qbfC9Wc9Anlx4I7PXqJ8rygSrxU8him
QhExutff7TC4yA2nPVLvGJV96eAl9nQdiux8EKhvJ4y66/e4IqFNVYtiyCpH2epv
rLRgWCmpBDONHL2LM82HJZXKtU8rwRUCsKnt2pjRR2BTEkCH5GNQasLI76TEorV3
Z+d8LWBHZgmsbR2BcCv7eSd29NAMoRalCx1emEJm/yizzXm3ADlH9PWR9bwuwMxx
IRcB1EsKXpWlzaJY3TfJ8p1cUqcx3Dm8majSb9nkTkbH5XuVf2hipz1URpYlcDjk
DUcFWbs+2BqLU9Gg4mZJMHc6XDsduv+sjaA5D8w5bYZfgqLA39/LPKPQCQ2vcYIm
CviivD2WpDXdkp2BFNV3lX/H6Vnlc2Mc6utUxMem2Ip7bBISIGayZKHyjOsAU+hh
T/giRQe8jtPFNh+pnEWBo83XMalqn0V5C7m/Jwb28bc7IPtPPlRcfYsnhY5y
-----END CERTIFICATE-----
EOF
if [ -x /usr/bin/curl ]; then
/usr/bin/curl -o /dev/null -H 'Content-Type: text/plain' --fail --noproxy \* --cacert $SSL_CA_CERT --silent 'https://satl01.lab.cudanet.org/unattended/built?token=10fd076d-92f5-4f80-83ad-3cb330ac4069'
elif [ -x /usr/bin/wget ]; then
/usr/bin/wget -q -O /dev/null --method POST --header 'Content-Type: text/plain' --no-proxy --ca-certificate $SSL_CA_CERT 'https://satl01.lab.cudanet.org/unattended/built?token=10fd076d-92f5-4f80-83ad-3cb330ac4069'
else
wget -q -O /dev/null --header 'Content-Type: text/plain' 'https://satl01.lab.cudanet.org/unattended/built?token=10fd076d-92f5-4f80-83ad-3cb330ac4069'
fi
FINAL_STATUS=$?
if [ -x "$(command -v subscription-manager)" ] ; then
subscription-manager facts --update
SUB_MAN_STATUS=$?
if [ $FINAL_STATUS -eq 0 ]; then
FINAL_STATUS=$SUB_MAN_STATUS
fi
fi
(exit $FINAL_STATUS);
if [[ $? == 0 ]] ; then
echo "Host [control-plane.k8s.lab.cudanet.org] successfully configured."
else
echo "ERROR: Host [control-plane.k8s.lab.cudanet.org] configured, but failed to report status to Foreman." >&2
exit 1
fi
subscription-manager repos
exit 0
+1
View File
@@ -0,0 +1 @@
no AI here. literally just followed the instructions https://goteleport.com/docs/installation/self-hosted/helm-deployments/kubernetes-cluster/
+19
View File
@@ -0,0 +1,19 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
annotations:
name: letsencrypt
namespace: teleport-cluster
spec:
commonName: 'teleport.k8s.lab.cudanet.org'
dnsNames:
- 'teleport.k8s.lab.cudanet.org'
duration: 2160h0m0s
issuerRef:
kind: ClusterIssuer
name: letsencrypt
renewBefore: 360h0m0s
secretName: letsencrypt
usages:
- server auth
- client auth
+22
View File
@@ -0,0 +1,22 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: teleport-ingress
namespace: teleport-cluster
annotations:
spec:
tls:
- hosts:
- teleport.k8s.lab.cudanet.org
secretName: letsencrypt
rules:
- host: teleport.k8s.lab.cudanet.org
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: teleport-cluster
port:
number: 443
+26
View File
@@ -0,0 +1,26 @@
---
apiVersion: traefik.io/v1alpha1
kind: ServersTransport
metadata:
name: teleport-backend-transport
namespace: teleport-cluster
spec:
insecureSkipVerify: true
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: teleport-web
namespace: teleport-cluster
spec:
entryPoints:
- websecure
routes:
- match: Host(`teleport.k8s.lab.cudanet.org`)
kind: Rule
services:
- name: teleport-cluster
port: 443
scheme: https # Crucial if Teleport expects HTTPS internally
tls:
secretName: letsencrypt
+10
View File
@@ -0,0 +1,10 @@
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: teleport-headers
namespace: teleport-cluster
spec:
headers:
customRequestHeaders:
X-Forwarded-Proto: "https"
X-Forwarded-Ssl: "on"
+3
View File
@@ -0,0 +1,3 @@
clusterName: clusterName
proxyListenerMode: multiplex
acme: false
+3
View File
@@ -0,0 +1,3 @@
I did rely on AI to help deploy Traefik since it had been several years since the last time I'd done so. Traefik has a lot of "knobs to fiddle with" when deploying and I wanted the simplest, most straightforward way to handle it. Specifically, I wanted Openshift wildcard route style ingress eg; my-app.k8s.lab.cudanet.org, vs. the other way Traefik is often configured with apps as subpaths, eg; traefik.k8s.lab.cudanet.org/my-app. Not what I wanted.
Once you meet the requirements for Traefik - ie; need a LoadBalancer provider like MetalLB. Need CSI set up to provision PVCs, Traefik is pretty straightforward. You do also have to create your wildcard DNS entry once your LB is provisioned though.
+43
View File
@@ -0,0 +1,43 @@
# Enable API & Dashboard
api:
dashboard: true
insecure: true
# Define ports
ports:
web:
port: 8000
exposedPort: 80
websecure:
port: 8443
exposedPort: 443
# Enable SafeNaming and allow cross-namespace routing
providers:
kubernetesCRD:
allowCrossNamespace: true
# If you want to enable the dashboard via IngressRoute
ingressRoute:
dashboard:
enabled: true
# Traefik static arguments for HTTP->HTTPS redirect & Let's Encrypt DNS-01 (Cloudflare)
additionalArguments:
- "--providers.kubernetescrd.safenaming=true"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge=true"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare"
- "--certificatesresolvers.letsencrypt.acme.email=admin@cudanet.org"
- "--certificatesresolvers.letsencrypt.acme.storage=/data/acme.json"
env:
- name: CF_DNS_API_TOKEN
value: "<changeme>"
# Match existing 128Mi size to satisfy immutability checks
persistence:
enabled: true
path: /data
size: 1Gi
+20
View File
@@ -0,0 +1,20 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: traefik-dashboard-wildcard
namespace: traefik
spec:
entryPoints:
- websecure
routes:
- match: Host(`traefik.k8s.lab.cudanet.org`) && (PathPrefix(`/dashboard`) || PathPrefix(`/api`))
kind: Rule
services:
- name: api@internal
kind: TraefikService
tls:
certResolver: letsencrypt
domains:
- main: "*.k8s.lab.cudanet.org"
sans:
- "k8s.lab.cudanet.org"