Server: Add support for hetzner csi with encryption
This commit is contained in:
parent
f0fa8d5ca5
commit
5bd824dee5
14 changed files with 644 additions and 3 deletions
18
README.md
18
README.md
|
@ -106,6 +106,24 @@ To provision the grafana agent only to an existing k8s system, ensure that the c
|
|||
provs-server.jar k3s myuser@myhost.com -o grafana
|
||||
```
|
||||
|
||||
To add the hetzner csi driver and encrypted volumes to your k3s installation add the following to the config:
|
||||
|
||||
```yaml
|
||||
hetzner:
|
||||
hcloudApiToken:
|
||||
source: "PLAIN" # PLAIN, GOPASS or PROMPT
|
||||
parameter: "mypassword" # the api key for the hetzner cloud
|
||||
encryptionPassphrase:
|
||||
source: "PLAIN" # PLAIN, GOPASS or PROMPT
|
||||
parameter: "mypassword" # the encryption passphrase for created volumes
|
||||
```
|
||||
|
||||
To provision the grafana agent only to an existing k8s system, ensure that the config (as above) is available and execute:
|
||||
|
||||
```bash
|
||||
provs-server.jar k3s myuser@myhost.com -o grafana
|
||||
```
|
||||
|
||||
Reprovisioning the server can easily be done using the -r or --reprovision option.
|
||||
|
||||
```bash
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package org.domaindrivenarchitecture.provs.server.domain.hetzner_csi
|
||||
|
||||
import org.domaindrivenarchitecture.provs.framework.core.Prov
|
||||
import org.domaindrivenarchitecture.provs.server.infrastructure.provisionHetznerCSIForK8s
|
||||
|
||||
fun Prov.provisionHetznerCSI(configResolved: HetznerCSIConfigResolved) =
|
||||
provisionHetznerCSIForK8s(configResolved.hcloudApiToken, configResolved.encryptionPassphrase)
|
|
@ -0,0 +1,23 @@
|
|||
package org.domaindrivenarchitecture.provs.server.domain.hetzner_csi
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.domaindrivenarchitecture.provs.framework.core.Secret
|
||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.secret.SecretSupplier
|
||||
|
||||
@Serializable
|
||||
data class HetznerCSIConfig (
|
||||
val hcloudApiToken: SecretSupplier,
|
||||
val encryptionPassphrase: SecretSupplier,
|
||||
) {
|
||||
fun resolveSecret(): HetznerCSIConfigResolved = HetznerCSIConfigResolved(this)
|
||||
}
|
||||
|
||||
data class HetznerCSIConfigResolved(val configUnresolved: HetznerCSIConfig) {
|
||||
val hcloudApiToken: Secret = configUnresolved.hcloudApiToken.secret()
|
||||
val encryptionPassphrase: Secret = configUnresolved.encryptionPassphrase.secret()
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class HetznerCSIConfigHolder(
|
||||
val hetzner: HetznerCSIConfig
|
||||
)
|
|
@ -2,6 +2,8 @@ package org.domaindrivenarchitecture.provs.server.domain.k3s
|
|||
|
||||
import org.domaindrivenarchitecture.provs.configuration.infrastructure.DefaultConfigFileRepository
|
||||
import org.domaindrivenarchitecture.provs.framework.core.Prov
|
||||
import org.domaindrivenarchitecture.provs.server.domain.hetzner_csi.HetznerCSIConfigResolved
|
||||
import org.domaindrivenarchitecture.provs.server.domain.hetzner_csi.provisionHetznerCSI
|
||||
import org.domaindrivenarchitecture.provs.server.domain.k8s_grafana_agent.GrafanaAgentConfigResolved
|
||||
import org.domaindrivenarchitecture.provs.server.domain.k8s_grafana_agent.provisionGrafanaAgent
|
||||
import org.domaindrivenarchitecture.provs.server.infrastructure.*
|
||||
|
@ -11,6 +13,7 @@ import kotlin.system.exitProcess
|
|||
fun Prov.provisionK3sCommand(cli: K3sCliCommand) = task {
|
||||
|
||||
val grafanaConfigResolved: GrafanaAgentConfigResolved? = findK8sGrafanaConfig(cli.configFileName)?.resolveSecret()
|
||||
val hcloudConfigResolved: HetznerCSIConfigResolved? = findHetznerCSIConfig(cli.configFileName)?.resolveSecret()
|
||||
|
||||
if (cli.onlyModules == null) {
|
||||
val k3sConfig: K3sConfig = getK3sConfig(cli.configFileName)
|
||||
|
@ -18,9 +21,10 @@ fun Prov.provisionK3sCommand(cli: K3sCliCommand) = task {
|
|||
val k3sConfigReprovision = k3sConfig.copy(reprovision = cli.reprovision || k3sConfig.reprovision)
|
||||
|
||||
val applicationFile = cli.applicationFileName?.let { DefaultApplicationFileRepository(cli.applicationFileName).getFile() }
|
||||
provisionK3s(k3sConfigReprovision, grafanaConfigResolved, applicationFile)
|
||||
provisionK3s(k3sConfigReprovision, grafanaConfigResolved, hcloudConfigResolved, applicationFile)
|
||||
} else {
|
||||
provisionGrafana(cli.onlyModules, grafanaConfigResolved)
|
||||
provisionHetznerCSI(cli.onlyModules, hcloudConfigResolved)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,6 +34,7 @@ fun Prov.provisionK3sCommand(cli: K3sCliCommand) = task {
|
|||
fun Prov.provisionK3s(
|
||||
k3sConfig: K3sConfig,
|
||||
grafanaConfigResolved: GrafanaAgentConfigResolved? = null,
|
||||
hetznerCSIConfigResolved: HetznerCSIConfigResolved? = null,
|
||||
applicationFile: ApplicationFile? = null
|
||||
) = task {
|
||||
|
||||
|
@ -53,6 +58,10 @@ fun Prov.provisionK3s(
|
|||
provisionGrafanaAgent(grafanaConfigResolved)
|
||||
}
|
||||
|
||||
if (hetznerCSIConfigResolved != null) {
|
||||
provisionHetznerCSI(hetznerCSIConfigResolved)
|
||||
}
|
||||
|
||||
if (applicationFile != null) {
|
||||
provisionK3sApplication(applicationFile)
|
||||
}
|
||||
|
@ -75,3 +84,18 @@ private fun Prov.provisionGrafana(
|
|||
provisionGrafanaAgent(grafanaConfigResolved)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Prov.provisionHetznerCSI(
|
||||
onlyModules: List<String>?,
|
||||
hetznerCSIConfigResolved: HetznerCSIConfigResolved?
|
||||
) = task {
|
||||
|
||||
if (onlyModules != null && onlyModules.contains(ServerOnlyModule.HETZNER_CSI.name.lowercase())) {
|
||||
if (hetznerCSIConfigResolved == null) {
|
||||
println("ERROR: Could not find grafana config.")
|
||||
exitProcess(7)
|
||||
}
|
||||
provisionHetznerCSI(hetznerCSIConfigResolved)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.domaindrivenarchitecture.provs.server.domain.k3s
|
||||
|
||||
enum class ServerOnlyModule {
|
||||
GRAFANA
|
||||
GRAFANA,
|
||||
HETZNER_CSI
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package org.domaindrivenarchitecture.provs.server.infrastructure
|
||||
|
||||
import org.domaindrivenarchitecture.provs.framework.core.Prov
|
||||
import org.domaindrivenarchitecture.provs.framework.core.Secret
|
||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createFileFromResource
|
||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.filesystem.base.createFileFromResourceTemplate
|
||||
import org.domaindrivenarchitecture.provs.server.domain.k3s.FileMode
|
||||
import java.io.File
|
||||
|
||||
private const val hetznerCSIResourceDir = "org/domaindrivenarchitecture/provs/server/infrastructure/hetznerCSI/"
|
||||
fun Prov.provisionHetznerCSIForK8s(hetznerApiToken: Secret, encryptionPassphrase: Secret) {
|
||||
// CSI Driver
|
||||
createFileFromResourceTemplate(
|
||||
k3sManualManifestsDir + "hcloud-api-token-secret.yaml",
|
||||
"hcloud-api-token-secret.template.yaml",
|
||||
resourcePath = hetznerCSIResourceDir,
|
||||
posixFilePermission = "644",
|
||||
values = mapOf(
|
||||
"HETZNER_API_TOKEN" to hetznerApiToken.plain()
|
||||
))
|
||||
applyHetznerCSIFileFromResource(File(k3sManualManifestsDir, "hcloud-api-token-secret.yaml"))
|
||||
applyHetznerCSIFileFromResource(File(k3sManualManifestsDir, "hcloud-csi.yaml"))
|
||||
|
||||
// Encryption
|
||||
createFileFromResourceTemplate(
|
||||
k3sManualManifestsDir + "hcloud-encryption-secret.yaml",
|
||||
"hcloud-encryption-secret.template.yaml",
|
||||
resourcePath = hetznerCSIResourceDir,
|
||||
posixFilePermission = "644",
|
||||
values = mapOf(
|
||||
"HETZNER_ENCRYPTION_PASSPHRASE" to encryptionPassphrase.plain()
|
||||
))
|
||||
applyHetznerCSIFileFromResource(File(k3sManualManifestsDir, "hcloud-encryption-secret.yaml"))
|
||||
applyHetznerCSIFileFromResource(File(k3sManualManifestsDir, "hcloud-encrypted-storage-class.yaml"))
|
||||
}
|
||||
|
||||
private fun Prov.createHetznerCSIFileFromResource(
|
||||
file: File,
|
||||
posixFilePermission: FileMode? = "644"
|
||||
) = task {
|
||||
createFileFromResource(
|
||||
file.path,
|
||||
file.name,
|
||||
hetznerCSIResourceDir,
|
||||
posixFilePermission,
|
||||
sudo = true
|
||||
)
|
||||
}
|
||||
|
||||
private fun Prov.applyHetznerCSIFileFromResource(file: File, posixFilePermission: FileMode? = "644") = task {
|
||||
createHetznerCSIFileFromResource(file, posixFilePermission)
|
||||
cmd("kubectl apply -f ${file.path}", sudo = true)
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package org.domaindrivenarchitecture.provs.server.infrastructure
|
||||
|
||||
import com.charleskorn.kaml.MissingRequiredPropertyException
|
||||
import org.domaindrivenarchitecture.provs.configuration.domain.ConfigFileName
|
||||
import org.domaindrivenarchitecture.provs.framework.core.readFromFile
|
||||
import org.domaindrivenarchitecture.provs.framework.core.toYaml
|
||||
import org.domaindrivenarchitecture.provs.framework.core.yamlToType
|
||||
import org.domaindrivenarchitecture.provs.server.domain.hetzner_csi.HetznerCSIConfig
|
||||
import org.domaindrivenarchitecture.provs.server.domain.hetzner_csi.HetznerCSIConfigHolder
|
||||
import java.io.File
|
||||
import java.io.FileWriter
|
||||
|
||||
private const val DEFAULT_CONFIG_FILE = "server-config.yaml"
|
||||
|
||||
fun findHetznerCSIConfig(fileName: ConfigFileName? = null): HetznerCSIConfig? {
|
||||
val filePath = fileName?.fileName ?: DEFAULT_CONFIG_FILE
|
||||
|
||||
return if(File(filePath).exists()) {
|
||||
try {
|
||||
readFromFile(filePath).yamlToType<HetznerCSIConfigHolder>().hetzner
|
||||
} catch (e: MissingRequiredPropertyException) {
|
||||
if (e.message.contains("Property 'hetzner'")) null else throw e
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
internal fun writeConfig(config: HetznerCSIConfigHolder, fileName: String = "hetzner-config.yaml") =
|
||||
FileWriter(fileName).use { it.write(config.toYaml()) }
|
|
@ -37,8 +37,9 @@ private val k3sEchoWithTls = File(k3sManualManifestsDir, "echo-tls.yaml")
|
|||
private val k3sEchoNoTls = File(k3sManualManifestsDir, "echo-no-tls.yaml")
|
||||
private val selfSignedCertificate = File(k3sManualManifestsDir, "selfsigned-certificate.yaml")
|
||||
|
||||
private val localPathProvisionerConfig = File(k3sManualManifestsDir, "local-path-provisioner-config.yaml")
|
||||
private val hetznerCSIDriver = File(k3sManualManifestsDir, "hcloud-csi.yaml")
|
||||
|
||||
private val localPathProvisionerConfig = File(k3sManualManifestsDir, "local-path-provisioner-config.yaml")
|
||||
|
||||
// ----------------------------------- public functions --------------------------------
|
||||
|
||||
|
@ -124,6 +125,10 @@ fun Prov.installK3s(k3sConfig: K3sConfig): ProvResult {
|
|||
applyK3sFileFromResource(k3sMiddleWareHttpsRedirect)
|
||||
}
|
||||
|
||||
// hetzner csi-driver
|
||||
applyK3sFileFromResource(hetznerCSIDriver)
|
||||
|
||||
// other
|
||||
applyK3sFileFromResource(localPathProvisionerConfig)
|
||||
|
||||
cmd("kubectl set env deployment -n kube-system local-path-provisioner DEPLOY_DATE=\"$(date)\"", sudo = true)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: hcloud
|
||||
namespace: kube-system
|
||||
stringData:
|
||||
token: $HETZNER_API_TOKEN
|
|
@ -0,0 +1,401 @@
|
|||
# Version 2.6.0
|
||||
# Source: hcloud-csi/templates/controller/serviceaccount.yaml
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: hcloud-csi-controller
|
||||
namespace: "kube-system"
|
||||
labels:
|
||||
app.kubernetes.io/name: hcloud-csi
|
||||
app.kubernetes.io/instance: hcloud-csi
|
||||
app.kubernetes.io/component: controller
|
||||
automountServiceAccountToken: true
|
||||
---
|
||||
# Source: hcloud-csi/templates/core/storageclass.yaml
|
||||
kind: StorageClass
|
||||
apiVersion: storage.k8s.io/v1
|
||||
metadata:
|
||||
name: hcloud-volumes
|
||||
annotations:
|
||||
storageclass.kubernetes.io/is-default-class: "true"
|
||||
provisioner: csi.hetzner.cloud
|
||||
volumeBindingMode: WaitForFirstConsumer
|
||||
allowVolumeExpansion: true
|
||||
reclaimPolicy: "Delete"
|
||||
---
|
||||
# Source: hcloud-csi/templates/controller/clusterrole.yaml
|
||||
kind: ClusterRole
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: hcloud-csi-controller
|
||||
labels:
|
||||
app.kubernetes.io/name: hcloud-csi
|
||||
app.kubernetes.io/instance: hcloud-csi
|
||||
app.kubernetes.io/component: controller
|
||||
rules:
|
||||
# attacher
|
||||
- apiGroups: [""]
|
||||
resources: [persistentvolumes]
|
||||
verbs: [get, list, watch, update, patch]
|
||||
- apiGroups: [""]
|
||||
resources: [nodes]
|
||||
verbs: [get, list, watch]
|
||||
- apiGroups: [csi.storage.k8s.io]
|
||||
resources: [csinodeinfos]
|
||||
verbs: [get, list, watch]
|
||||
- apiGroups: [storage.k8s.io]
|
||||
resources: [csinodes]
|
||||
verbs: [get, list, watch]
|
||||
- apiGroups: [storage.k8s.io]
|
||||
resources: [volumeattachments]
|
||||
verbs: [get, list, watch, update, patch]
|
||||
- apiGroups: [storage.k8s.io]
|
||||
resources: [volumeattachments/status]
|
||||
verbs: [patch]
|
||||
# provisioner
|
||||
- apiGroups: [""]
|
||||
resources: [secrets]
|
||||
verbs: [get, list]
|
||||
- apiGroups: [""]
|
||||
resources: [persistentvolumes]
|
||||
verbs: [get, list, watch, create, delete, patch]
|
||||
- apiGroups: [""]
|
||||
resources: [persistentvolumeclaims, persistentvolumeclaims/status]
|
||||
verbs: [get, list, watch, update, patch]
|
||||
- apiGroups: [storage.k8s.io]
|
||||
resources: [storageclasses]
|
||||
verbs: [get, list, watch]
|
||||
- apiGroups: [""]
|
||||
resources: [events]
|
||||
verbs: [list, watch, create, update, patch]
|
||||
- apiGroups: [snapshot.storage.k8s.io]
|
||||
resources: [volumesnapshots]
|
||||
verbs: [get, list]
|
||||
- apiGroups: [snapshot.storage.k8s.io]
|
||||
resources: [volumesnapshotcontents]
|
||||
verbs: [get, list]
|
||||
# resizer
|
||||
- apiGroups: [""]
|
||||
resources: [pods]
|
||||
verbs: [get, list, watch]
|
||||
# node
|
||||
- apiGroups: [""]
|
||||
resources: [events]
|
||||
verbs: [get, list, watch, create, update, patch]
|
||||
---
|
||||
# Source: hcloud-csi/templates/controller/clusterrolebinding.yaml
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: hcloud-csi-controller
|
||||
labels:
|
||||
app.kubernetes.io/name: hcloud-csi
|
||||
app.kubernetes.io/instance: hcloud-csi
|
||||
app.kubernetes.io/component: controller
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: hcloud-csi-controller
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: hcloud-csi-controller
|
||||
namespace: "kube-system"
|
||||
---
|
||||
# Source: hcloud-csi/templates/controller/service.yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: hcloud-csi-controller-metrics
|
||||
namespace: "kube-system"
|
||||
labels:
|
||||
app.kubernetes.io/name: hcloud-csi
|
||||
app.kubernetes.io/instance: hcloud-csi
|
||||
app.kubernetes.io/component: controller
|
||||
spec:
|
||||
ports:
|
||||
- name: metrics
|
||||
port: 9189
|
||||
selector:
|
||||
app.kubernetes.io/name: hcloud-csi
|
||||
app.kubernetes.io/instance: hcloud-csi
|
||||
app.kubernetes.io/component: controller
|
||||
---
|
||||
# Source: hcloud-csi/templates/node/service.yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: hcloud-csi-node-metrics
|
||||
namespace: "kube-system"
|
||||
labels:
|
||||
app.kubernetes.io/name: hcloud-csi
|
||||
app.kubernetes.io/instance: hcloud-csi
|
||||
app.kubernetes.io/component: node
|
||||
spec:
|
||||
ports:
|
||||
- name: metrics
|
||||
port: 9189
|
||||
selector:
|
||||
app.kubernetes.io/name: hcloud-csi
|
||||
app.kubernetes.io/instance: hcloud-csi
|
||||
app.kubernetes.io/component: node
|
||||
---
|
||||
# Source: hcloud-csi/templates/node/daemonset.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: hcloud-csi-node
|
||||
namespace: "kube-system"
|
||||
labels:
|
||||
app.kubernetes.io/name: hcloud-csi
|
||||
app.kubernetes.io/instance: hcloud-csi
|
||||
app.kubernetes.io/component: node
|
||||
app: hcloud-csi
|
||||
spec:
|
||||
updateStrategy:
|
||||
type: RollingUpdate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: hcloud-csi
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: hcloud-csi
|
||||
app.kubernetes.io/instance: hcloud-csi
|
||||
app.kubernetes.io/component: node
|
||||
app: hcloud-csi
|
||||
spec:
|
||||
|
||||
affinity:
|
||||
nodeAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
nodeSelectorTerms:
|
||||
- matchExpressions:
|
||||
- key: instance.hetzner.cloud/is-root-server
|
||||
operator: NotIn
|
||||
values:
|
||||
- "true"
|
||||
tolerations:
|
||||
- effect: NoExecute
|
||||
operator: Exists
|
||||
- effect: NoSchedule
|
||||
operator: Exists
|
||||
- key: CriticalAddonsOnly
|
||||
operator: Exists
|
||||
securityContext:
|
||||
fsGroup: 1001
|
||||
initContainers:
|
||||
containers:
|
||||
- name: csi-node-driver-registrar
|
||||
image: registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.7.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
args:
|
||||
- --kubelet-registration-path=/var/lib/kubelet/plugins/csi.hetzner.cloud/socket
|
||||
volumeMounts:
|
||||
- name: plugin-dir
|
||||
mountPath: /run/csi
|
||||
- name: registration-dir
|
||||
mountPath: /registration
|
||||
resources:
|
||||
limits: {}
|
||||
requests: {}
|
||||
- name: liveness-probe
|
||||
image: registry.k8s.io/sig-storage/livenessprobe:v2.9.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
volumeMounts:
|
||||
- mountPath: /run/csi
|
||||
name: plugin-dir
|
||||
resources:
|
||||
limits: {}
|
||||
requests: {}
|
||||
- name: hcloud-csi-driver
|
||||
image: docker.io/hetznercloud/hcloud-csi-driver:v2.6.0 # x-release-please-version
|
||||
imagePullPolicy: IfNotPresent
|
||||
command: [/bin/hcloud-csi-driver-node]
|
||||
volumeMounts:
|
||||
- name: kubelet-dir
|
||||
mountPath: /var/lib/kubelet
|
||||
mountPropagation: "Bidirectional"
|
||||
- name: plugin-dir
|
||||
mountPath: /run/csi
|
||||
- name: device-dir
|
||||
mountPath: /dev
|
||||
securityContext:
|
||||
privileged: true
|
||||
env:
|
||||
- name: CSI_ENDPOINT
|
||||
value: unix:///run/csi/socket
|
||||
- name: METRICS_ENDPOINT
|
||||
value: "0.0.0.0:9189"
|
||||
- name: ENABLE_METRICS
|
||||
value: "true"
|
||||
ports:
|
||||
- containerPort: 9189
|
||||
name: metrics
|
||||
- name: healthz
|
||||
protocol: TCP
|
||||
containerPort: 9808
|
||||
resources:
|
||||
limits: {}
|
||||
requests: {}
|
||||
livenessProbe:
|
||||
failureThreshold: 5
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 2
|
||||
successThreshold: 1
|
||||
timeoutSeconds: 3
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: healthz
|
||||
volumes:
|
||||
- name: kubelet-dir
|
||||
hostPath:
|
||||
path: /var/lib/kubelet
|
||||
type: Directory
|
||||
- name: plugin-dir
|
||||
hostPath:
|
||||
path: /var/lib/kubelet/plugins/csi.hetzner.cloud/
|
||||
type: DirectoryOrCreate
|
||||
- name: registration-dir
|
||||
hostPath:
|
||||
path: /var/lib/kubelet/plugins_registry/
|
||||
type: Directory
|
||||
- name: device-dir
|
||||
hostPath:
|
||||
path: /dev
|
||||
type: Directory
|
||||
---
|
||||
# Source: hcloud-csi/templates/controller/deployment.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: hcloud-csi-controller
|
||||
namespace: "kube-system"
|
||||
labels:
|
||||
app.kubernetes.io/name: hcloud-csi
|
||||
app.kubernetes.io/instance: hcloud-csi
|
||||
app.kubernetes.io/component: controller
|
||||
app: hcloud-csi-controller
|
||||
spec:
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: hcloud-csi-controller
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: hcloud-csi
|
||||
app.kubernetes.io/instance: hcloud-csi
|
||||
app.kubernetes.io/component: controller
|
||||
app: hcloud-csi-controller
|
||||
spec:
|
||||
serviceAccountName: hcloud-csi-controller
|
||||
|
||||
securityContext:
|
||||
fsGroup: 1001
|
||||
initContainers:
|
||||
containers:
|
||||
- name: csi-attacher
|
||||
image: registry.k8s.io/sig-storage/csi-attacher:v4.1.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
resources:
|
||||
limits: {}
|
||||
requests: {}
|
||||
args:
|
||||
- --default-fstype=ext4
|
||||
volumeMounts:
|
||||
- name: socket-dir
|
||||
mountPath: /run/csi
|
||||
|
||||
- name: csi-resizer
|
||||
image: registry.k8s.io/sig-storage/csi-resizer:v1.7.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
resources:
|
||||
limits: {}
|
||||
requests: {}
|
||||
volumeMounts:
|
||||
- name: socket-dir
|
||||
mountPath: /run/csi
|
||||
|
||||
- name: csi-provisioner
|
||||
image: registry.k8s.io/sig-storage/csi-provisioner:v3.4.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
resources:
|
||||
limits: {}
|
||||
requests: {}
|
||||
args:
|
||||
- --feature-gates=Topology=true
|
||||
- --default-fstype=ext4
|
||||
volumeMounts:
|
||||
- name: socket-dir
|
||||
mountPath: /run/csi
|
||||
|
||||
- name: liveness-probe
|
||||
image: registry.k8s.io/sig-storage/livenessprobe:v2.9.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
resources:
|
||||
limits: {}
|
||||
requests: {}
|
||||
volumeMounts:
|
||||
- mountPath: /run/csi
|
||||
name: socket-dir
|
||||
|
||||
- name: hcloud-csi-driver
|
||||
image: docker.io/hetznercloud/hcloud-csi-driver:v2.6.0 # x-release-please-version
|
||||
imagePullPolicy: IfNotPresent
|
||||
command: [/bin/hcloud-csi-driver-controller]
|
||||
env:
|
||||
- name: CSI_ENDPOINT
|
||||
value: unix:///run/csi/socket
|
||||
- name: METRICS_ENDPOINT
|
||||
value: "0.0.0.0:9189"
|
||||
- name: ENABLE_METRICS
|
||||
value: "true"
|
||||
- name: KUBE_NODE_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
apiVersion: v1
|
||||
fieldPath: spec.nodeName
|
||||
- name: HCLOUD_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: hcloud
|
||||
key: token
|
||||
resources:
|
||||
limits: {}
|
||||
requests: {}
|
||||
ports:
|
||||
- name: metrics
|
||||
containerPort: 9189
|
||||
- name: healthz
|
||||
protocol: TCP
|
||||
containerPort: 9808
|
||||
livenessProbe:
|
||||
failureThreshold: 5
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 2
|
||||
successThreshold: 1
|
||||
timeoutSeconds: 3
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: healthz
|
||||
volumeMounts:
|
||||
- name: socket-dir
|
||||
mountPath: /run/csi
|
||||
|
||||
volumes:
|
||||
- name: socket-dir
|
||||
emptyDir: {}
|
||||
---
|
||||
# Source: hcloud-csi/templates/core/csidriver.yaml
|
||||
apiVersion: storage.k8s.io/v1
|
||||
kind: CSIDriver
|
||||
metadata:
|
||||
name: csi.hetzner.cloud
|
||||
spec:
|
||||
attachRequired: true
|
||||
fsGroupPolicy: File
|
||||
podInfoOnMount: true
|
||||
volumeLifecycleModes:
|
||||
- Persistent
|
|
@ -0,0 +1,11 @@
|
|||
apiVersion: storage.k8s.io/v1
|
||||
kind: StorageClass
|
||||
metadata:
|
||||
name: hcloud-volumes-encrypted
|
||||
provisioner: csi.hetzner.cloud
|
||||
reclaimPolicy: Delete
|
||||
volumeBindingMode: WaitForFirstConsumer
|
||||
allowVolumeExpansion: true
|
||||
parameters:
|
||||
csi.storage.k8s.io/node-publish-secret-name: encryption-secret
|
||||
csi.storage.k8s.io/node-publish-secret-namespace: kube-system
|
|
@ -0,0 +1,7 @@
|
|||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: encryption-secret
|
||||
namespace: kube-system
|
||||
stringData:
|
||||
encryption-passphrase: $HETZNER_ENCRYPTION_PASSPHRASE
|
|
@ -0,0 +1,35 @@
|
|||
package org.domaindrivenarchitecture.provs.server.infrastructure
|
||||
|
||||
import org.domaindrivenarchitecture.provs.configuration.domain.ConfigFileName
|
||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.secret.SecretSourceType
|
||||
import org.domaindrivenarchitecture.provs.framework.ubuntu.secret.SecretSupplier
|
||||
import org.domaindrivenarchitecture.provs.server.domain.hetzner_csi.HetznerCSIConfig
|
||||
import org.domaindrivenarchitecture.provs.server.domain.k8s_grafana_agent.GrafanaAgentConfig
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
internal class HetznerCSIRepositoryKtTest {
|
||||
|
||||
@Test
|
||||
fun findHetznerCSIConfig_returns_config() {
|
||||
// when
|
||||
val config = findHetznerCSIConfig(ConfigFileName("src/test/resources/k3s-server-config-with-hetzner.yaml"))
|
||||
|
||||
// then
|
||||
assertEquals(
|
||||
HetznerCSIConfig(
|
||||
hcloudApiToken = SecretSupplier(SecretSourceType.GOPASS, "path/to/apitoken"),
|
||||
encryptionPassphrase = SecretSupplier(SecretSourceType.GOPASS, "path/to/encryption"),
|
||||
), config
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun findHetznerCSIConfig_returns_null_if_no_hetzner_data_available() {
|
||||
// when
|
||||
val config = findHetznerCSIConfig(ConfigFileName("src/test/resources/k3s-server-config.yaml"))
|
||||
|
||||
// then
|
||||
assertEquals(null, config)
|
||||
}
|
||||
}
|
18
src/test/resources/k3s-server-config-with-hetzner.yaml
Normal file
18
src/test/resources/k3s-server-config-with-hetzner.yaml
Normal file
|
@ -0,0 +1,18 @@
|
|||
fqdn: statistics.test.meissa-gmbh.de
|
||||
node:
|
||||
ipv4: 162.55.164.138
|
||||
ipv6: 2a01:4f8:c010:672f::1
|
||||
certmanager:
|
||||
email: admin@meissa-gmbh.de
|
||||
letsencryptEndpoint: prod
|
||||
echo: true
|
||||
reprovision: true
|
||||
|
||||
|
||||
hetzner:
|
||||
hcloudApiToken:
|
||||
source: "GOPASS" # PLAIN, GOPASS or PROMPT
|
||||
parameter: "path/to/apitoken" # the api key for the hetzner cloud
|
||||
encryptionPassphrase:
|
||||
source: "GOPASS" # PLAIN, GOPASS or PROMPT
|
||||
parameter: "path/to/encryption" # the encryption passphrase for created volumes
|
Loading…
Reference in a new issue