Skip to content

Commit

Permalink
k3d deployment v2
Browse files Browse the repository at this point in the history
more declarative, installs higher version, but still lacks some
functionality of the version in adjacent "k3d" directory.
  • Loading branch information
mouchar committed Jul 17, 2024
1 parent fb10b3a commit 94cc6b1
Show file tree
Hide file tree
Showing 11 changed files with 945 additions and 0 deletions.
5 changes: 5 additions & 0 deletions k3d-local/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ca.crt
ca.key
ca-secret.yaml
ca-issuer.yaml
gooddata-license.env
161 changes: 161 additions & 0 deletions k3d-local/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
g GoodData.CN in K3D
This script allows you to deploy a 3-node Kubernetes cluster on your local
machine within docker containers, deploy Apache Pulsar and GoodData.CN,
configure cert-manager with self-signed certificate authority and set up
Ningx ingress controller.

## Requirements

HW requirements are pretty high, I recommend at least 8 CPU cores and 12 GB
RAM available to Docker. Only `x86_64` CPU architecture is supported.

Here is a list of things you need to have installed before running the script:
* [k3d](https://github.com/rancher/k3d/releases/tag/v5.4.0) 5.4,x
* [kubectl](https://kubernetes.io/docs/tasks/tools/) 1.24 or higher
* openssl 1.x
* [Helm](https://helm.sh/docs/intro/install/) 3.x
* [Docker](https://www.docker.com/)
* envsubst (part of gettext)
* (optional but recommended) [crane](https://github.com/google/go-containerregistry/blob/main/cmd/crane/README.md)

Environment variables that need to be set:
* `GDCN_LICENSE` contaning GoodData.CN license key

These services must be running and accessible by the user running the script:
* Docker daemon

Store your GoodData.CN license to environment variable GDCN_LICENSE:
```
export GDCN_LICENSE="key/......."
```

## Configuration
```
Usage: ./k3d.sh [options]
Options are:
-c - create cluster
-v VERSION - use this version of gooddata-cn helm chart
-f FILE - full path to a yaml with GD.CN helm values
```

`-c` should be used to create or recreate cluster. If you want just update
existing cluster, do not use this parameter. Script will perform helm upgrade
of all components within existing cluster.

## Usage
```
./k3d.sh -c
```
The script pulls all images to local docker registry (to save network
bandwidth), creates 3-node kubernetes cluster, install apps, generates
CA certificate (the certificate is printed to output including the steps
describing how to add this certificate to your browser).

When script finishes, your kubeconfig is automatically set to your new
k3d cluster context. You can immediately use `kubectl` to control the cluster.

```
kubectl get node
NAME STATUS ROLES AGE VERSION
k3d-default-agent-1 Ready <none> 33m v1.26.6+k3s1
k3d-default-server-0 Ready control-plane,master 33m v1.26.6+k3s1
k3d-default-agent-0 Ready <none> 33m v1.26.6+k3s1
```

## What next?
Create Organization resource, and apply to cluster:

```
# contents of org-demo.yaml file
apiVersion: controllers.gooddata.com/v1
kind: Organization
metadata:
name: demo-org
namespace: gooddata
spec:
id: demo
name: Demo organization
hostname: localhost
adminGroup: adminGroup
adminUser: admin
adminUserToken: "$5$marO0ghT5pAg/CLe$ZiGVePUEPHryyEpSnnd9DmbLs4uNUKWGXjjmGnYT1NA"
tls:
secretName: demo-org-tls
issuerName: ca-issuer
```

Explanation of important attributes:
* `metadata.name` - name of Kubernetes resource
* `metadata.namespace` - where the Organization resource will be created
* `spec.id` - ID of organization in metadata
* `spec.name` - friendly name of organization
* `spec.hostname` - FQDN of organization endpoint. Ingress with the same host will be
created by the GoodData.CN
* `spec.adminUser` - name of initial organization administrator account
* `spec.adminUserToken` - SHA256 hash (salted) of the secret part of bootstrap
token
* `spec.tls.secretName` - name of k8s Secret where TLS certificate and key will
be stored by cert-manager
* `spec.tls.issuerName` - name of cert-manager's Issuer or ClusterIsuer
* `spec.tls.issuerType` - type of cert-manager's issuer. Either `Issuer` (default)
or `ClusterIssuer`.

The easiest way on how to generate salted hash from plaintext secret is:

```
docker run -it --rm alpine:latest mkpasswd -m sha256crypt example
$5$marO0ghT5pAg/CLe$ZiGVePUEPHryyEpSnnd9DmbLs4uNUKWGXjjmGnYT1NA
```

Apply organization resource:
```
kubectl apply -f org-demo.yaml
```

## Try accessing the organization
**Note**: As the system is using self-signed CA, you may also want to add its
certificate to your operating system and web browser.

To access organization for the first time, create so-called bootstrap token from
the secret you used to create `spec.adminUserToken` above. We used "example"
word as a secret, and "admin" as `spec.adminUser` account name. "bootstrap" is
given and can not be changed. Later on, you can create your own API tokens and
name them as you wish.

```
echo -n "admin:bootstrap:example" | base64
YWRtaW46Ym9vdHN0cmFwOmV4YW1wbGU=
```

So `YWRtaW46Ym9vdHN0cmFwOmV4YW1wbGU=` is your secret token you will use for
initial setup of the organization using JSON:API and REST API.

```
curl -k -H 'Authorization: Bearer YWRtaW46Ym9vdHN0cmFwOmV4YW1wbGU=' \
https://localhost/api/v1/entities/admin/organizations/demo
{
"data": {
"attributes": {
"name": "Demo organization",
"hostname": "localhost",
"oauthClientId": "114f0a8b-2335-4bf4-ba54-37e1ee04afe1"
},
"id": "demo",
"type": "organization"
},
"links": {
"self": "https://localhost/api/v1/entities/admin/organizations/demo"
}
}
```

## Next steps
Follow the [documentation](https://www.gooddata.com/developers/cloud-native/doc)
to learn more about adding users, configuring data sources and further steps.

## Cleanup
If you want to wipe the environment, perform these steps:
* delete k3d cluster: `k3d cluster delete default`
* remove registry volume: `docker volume rm registry-data`
19 changes: 19 additions & 0 deletions k3d-local/cert-manager.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apiVersion: v1
kind: Namespace
metadata:
name: cert-manager
---
apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
name: cert-manager
namespace: kube-system
spec:
repo: https://charts.jetstack.io
chart: cert-manager
version: v1.6.0
targetNamespace: cert-manager
valuesContent: |-
installCRDs: "true"
extraArgs:
- "--enable-certificate-owner-ref=true"
123 changes: 123 additions & 0 deletions k3d-local/gen_keys.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/bin/bash

# Creates local CA key/cert pair and configures cert-manager
# Issuer or ClusterIssuer (in case the namespace=cert-manager)
# Usage: $0 [namespace]
# Namespace defaults to "gooddata"

usage() {
cat > /dev/stderr <<EOT
Usage: $0 [options] [namespace]
Options are:
-k - resources will be loaded later by kustomize
EOT
exit 1
}

while getopts ":k" o; do
case "${o}" in
k)
NO_LOAD=yes
;;
*)
usage
;;
esac
done
shift $((OPTIND-1))

NAMESPACE=${1-gooddata}
COMMON_NAME="K3D Local CA"
CM_NAMESPACE="cert-manager"
CLUSTERWIDE=""

if [ "${NAMESPACE}" == "${CM_NAMESPACE}" ] ; then
echo "Given namespace is ${NAMESPACE}, creating ClusterIssuer"
CLUSTERWIDE="Cluster"
fi

if [ ! -f ca.key ] ; then
# Generate a CA private key
openssl genrsa -out ca.key 2048
else
echo "Reusing existing private key ca.key"
fi

if [ ! -f ca.crt ] ; then
# Create a self signed Certificate, valid for 10yrs with the 'signing' option set
openssl req -x509 -new -nodes -key ca.key -subj "/CN=${COMMON_NAME}" \
-days 7300 -reqexts v3_req -extensions v3_ca -out ca.crt
else
echo "Reusing existing CA certificate ca.crt"
fi

cat << EOF
If you wan't to suppress 'Untrusted certificate' errors in web browser,
install the following CA certificate to your system and browser:
$(cat ca.crt)
### On Linux with Chrome/Chromium browser, you can use this
### to set trust (needs libnss3-tools)
## sudo apt-get install libnss3-tools
### Create NSS db if it doesn't exist
## [ ! -d $HOME/.pki/nssdb ] && certutil -N -d sql:$HOME/.pki/nssdb --empty-password
## Load local CA Certificate as trusted to your system
## certutil -d sql:$HOME/.pki/nssdb -A -t C -n "$COMMON_NAME" -i $PWD/ca.crt
EOF

if [ "${NO_LOAD}" == "yes" ] ; then
echo "Skipping upload to cluster"
exit 0
fi

# MacOS has changed base64's command argument from version 13+ (Ventura)
case "$(uname -s)" in
Darwin*)
if [ $(sw_vers -productVersion | cut -d '.' -f 1) -ge 13 ] ; then
b64_opts="-i"
else
b64_opts="-b0"
fi
;;
*)
b64_opts="-w0"
;;
esac

cert=$(base64 $b64_opts ca.crt)
key=$(base64 $b64_opts ca.key)

# Create Secret
cat > ca-secret.yaml << EOF
apiVersion: v1
kind: Secret
type: kubernetes.io/tls
metadata:
name: ca-key-pair
namespace: ${NAMESPACE}
data:
tls.crt: $cert
tls.key: $key
EOF

# Create Issuer
cat > ca-issuer.yaml << EOF
apiVersion: cert-manager.io/v1
kind: ${CLUSTERWIDE}Issuer
metadata:
name: ca-issuer
namespace: ${NAMESPACE}
spec:
ca:
secretName: ca-key-pair
EOF

echo "Uploading resources to kuberenetes"
kubectl create -f ca-secret.yaml
kubectl create -f ca-issuer.yaml

rm ca-issuer.yaml ca-secret.yaml
18 changes: 18 additions & 0 deletions k3d-local/ingress-nginx.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
name: ingress-nginx
namespace: kube-system
spec:
repo: https://kubernetes.github.io/ingress-nginx
chart: ingress-nginx
version: 4.1.1
targetNamespace: kube-system
valuesContent: |-
controller:
config:
use-forwarded-headers: "true"
tolerations:
- key: "node-role.kubernetes.io/master"
operator: "Exists"
effect: "NoSchedule"
56 changes: 56 additions & 0 deletions k3d-local/k3d-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
apiVersion: k3d.io/v1alpha5
kind: Simple
metadata:
name: default
servers: 1
agents: 2
kubeAPI:
host: "localhost"
hostIP: "0.0.0.0"
hostPort: "6443"
# If not specified, the latest version will be used
# image: rancher/k3s:v1.30.1-k3s1
network: k3d-default
volumes:
- volume: "${PWD}/cert-manager.yaml:/var/lib/rancher/k3s/server/manifests/cert-manager.yaml"
nodeFilters:
- server:0
- volume: "${PWD}/ingress-nginx.yaml:/var/lib/rancher/k3s/server/manifests/ingress-nginx.yaml"
nodeFilters:
- server:0
ports:
- port: "${K3D_HTTPS_PORT}:443"
nodeFilters:
- loadbalancer
- port: "${K3D_HTTP_PORT}:80"
nodeFilters:
- loadbalancer
registries:
create:
name: k3d-registry
host: "0.0.0.0"
hostPort: "${DOCKER_REGISTRY_PORT}"
volumes:
- registry-data:/var/lib/registry
config: |
mirrors:
"k3d-registry:${DOCKER_REGISTRY_PORT}":
endpoint:
- http://k3d-registry:${DOCKER_REGISTRY_PORT}
options:
k3d:
wait: true
timeout: "60s"
k3s:
extraArgs:
- arg: --disable=traefik
nodeFilters:
- server:*
# nodeLabels:
# - label: role=infra
# nodeFilters:
# - agent:*
# - server:*
kubeconfig:
updateDefaultKubeconfig: true
switchCurrentContext: true
Loading

0 comments on commit 94cc6b1

Please sign in to comment.