Π Π½Π°ΡΠ΅ΠΌ Π±Π»ΠΎΠ³Π΅ ΡΠΆΠ΅ Π±ΡΠ»ΠΈ ΡΡΠ°ΡΡΠΈ, ΡΠ°ΡΡΠΊΠ°Π·ΡΠ²Π°ΡΡΠΈΠ΅ ΠΏΡΠΎ
ΠΠ°ΡΠ΅ΠΌ?
ΠΠ΄Π΅Ρ shell-operator Π΄ΠΎΠ²ΠΎΠ»ΡΠ½ΠΎ ΠΏΡΠΎΡΡΠ°: ΠΏΠΎΠ΄ΠΏΠΈΡΠ°ΡΡΡΡ Π½Π° ΡΠΎΠ±ΡΡΠΈΡ ΠΎΡ ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ² Kubernetes, Π° ΠΏΡΠΈ ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΠΈ ΡΡΠΈΡ ΡΠΎΠ±ΡΡΠΈΠΉ Π·Π°ΠΏΡΡΡΠΈΡΡ Π²Π½Π΅ΡΠ½ΡΡ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ, ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²ΠΈΠ² Π΅ΠΉ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ ΠΎ ΡΠΎΠ±ΡΡΠΈΠΈ:
ΠΠΎΡΡΠ΅Π±Π½ΠΎΡΡΡ Π² Π½ΡΠΌ Π²ΠΎΠ·Π½ΠΈΠΊΠ»Π° Ρ Π½Π°Ρ, ΠΊΠΎΠ³Π΄Π° ΠΏΡΠΈ ΡΠΊΡΠΏΠ»ΡΠ°ΡΠ°ΡΠΈΠΈ ΠΊΠ»Π°ΡΡΠ΅ΡΠΎΠ² ΡΡΠ°Π»ΠΈ ΠΏΠΎΡΠ²Π»ΡΡΡΡΡ ΠΌΠ΅Π»ΠΊΠΈΠ΅ Π·Π°Π΄Π°ΡΠΈ, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΎΡΠ΅Π½Ρ Ρ ΠΎΡΠ΅Π»ΠΎΡΡ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ ΠΏΡΠ°Π²ΠΈΠ»ΡΠ½ΡΠΌ ΠΏΡΡΡΠΌ. ΠΡΠ΅ ΡΡΠΈ ΠΌΠ΅Π»ΠΊΠΈΠ΅ Π·Π°Π΄Π°ΡΠΈ ΡΠ΅ΡΠ°Π»ΠΈΡΡ Ρ ΠΏΠΎΠΌΠΎΡΡΡ ΠΏΡΠΎΡΡΡΡ bash-ΡΠΊΡΠΈΠΏΡΠΎΠ², Ρ ΠΎΡΡ, ΠΊΠ°ΠΊ ΠΈΠ·Π²Π΅ΡΡΠ½ΠΎ, ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΡ Π»ΡΡΡΠ΅ ΠΏΠΈΡΠ°ΡΡ Π½Π° Golang. ΠΡΠ΅Π²ΠΈΠ΄Π½ΠΎ, ΡΡΠΎ Π²ΠΊΠ»Π°Π΄ΡΠ²Π°ΡΡΡΡ Π² ΠΏΠΎΠ»Π½ΠΎΠΌΠ°ΡΡΡΠ°Π±Π½ΡΡ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΡ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΠ° ΠΏΠΎΠ΄ ΠΊΠ°ΠΆΠ΄ΡΡ ΡΠ°ΠΊΡΡ ΠΌΠ΅Π»ΠΊΡΡ Π·Π°Π΄Π°ΡΡ Π±ΡΠ»ΠΎ Π±Ρ Π½Π΅ΡΡΡΠ΅ΠΊΡΠΈΠ²Π½ΠΎ.
ΠΠΏΠ΅ΡΠ°ΡΠΎΡ Π·Π° 15 ΠΌΠΈΠ½ΡΡ
Π Π°ΡΡΠΌΠΎΡΡΠΈΠΌ Π½Π° ΠΏΡΠΈΠΌΠ΅ΡΠ΅, ΡΡΠΎ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΠ·ΠΈΡΠΎΠ²Π°Π½ΠΎ Π² Kubernetes-ΠΊΠ»Π°ΡΡΠ΅ΡΠ΅ ΠΈ ΡΠ΅ΠΌ ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ shell-operator. ΠΡΠΈΠΌΠ΅Ρ ΠΆΠ΅ Π±ΡΠ΄Π΅Ρ ΡΠ»Π΅Π΄ΡΡΡΠΈΠΌ: ΡΠΈΡΠ°ΠΆΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΡΠ΅ΠΊΡΠ΅ΡΠ° Π΄Π»Ρ Π΄ΠΎΡΡΡΠΏΠ° ΠΊ docker registry.
Pod’Ρ, ΠΊΠΎΡΠΎΡΡΠ΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡΡ ΠΎΠ±ΡΠ°Π·Ρ ΠΈΠ· private registry, Π΄ΠΎΠ»ΠΆΠ½Ρ ΡΠΎΠ΄Π΅ΡΠΆΠ°ΡΡ Π² ΡΠ²ΠΎΡΠΌ ΠΌΠ°Π½ΠΈΡΠ΅ΡΡΠ΅ ΡΡΡΠ»ΠΊΡ Π½Π° ΡΠ΅ΠΊΡΠ΅Ρ Ρ Π΄Π°Π½Π½ΡΠΌΠΈ Π΄Π»Ρ Π΄ΠΎΡΡΡΠΏΠ° ΠΊ registry. ΠΡΠΎΡ ΡΠ΅ΠΊΡΠ΅Ρ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±ΡΡΡ ΡΠΎΠ·Π΄Π°Π½ Π² ΠΊΠ°ΠΆΠ΄ΠΎΠΌ namespace ΠΏΠ΅ΡΠ΅Π΄ ΡΠΎΠ·Π΄Π°Π½ΠΈΠ΅ΠΌ pod’ΠΎΠ². ΠΡΠΎ Π²ΠΏΠΎΠ»Π½Π΅ ΠΌΠΎΠΆΠ½ΠΎ Π΄Π΅Π»Π°ΡΡ ΠΈ Π²ΡΡΡΠ½ΡΡ, Π½ΠΎ Π΅ΡΠ»ΠΈ ΠΌΡ Π½Π°ΡΡΡΠΎΠΈΠΌ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΈΠ΅ ΠΎΠΊΡΡΠΆΠ΅Π½ΠΈΡ, ΡΠΎ namespace Π΄Π»Ρ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ ΡΡΠ°Π½Π΅Ρ ΠΌΠ½ΠΎΠ³ΠΎ. Π Π΅ΡΠ»ΠΈ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ ΡΠΎΠΆΠ΅ Π½Π΅ 2-3β¦ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ ΡΠ΅ΠΊΡΠ΅ΡΠΎΠ² ΡΡΠ°Π½ΠΎΠ²ΠΈΡΡΡ ΠΎΡΠ΅Π½Ρ Π±ΠΎΠ»ΡΡΠΈΠΌ. Π Π΅ΡΡ ΠΎΠ΄ΠΈΠ½ ΠΌΠΎΠΌΠ΅Π½Ρ ΠΏΡΠΎ ΡΠ΅ΠΊΡΠ΅ΡΡ: ΠΊΠ»ΡΡ Π΄Π»Ρ Π΄ΠΎΡΡΡΠΏΠ° ΠΊ registry Ρ ΠΎΡΠ΅Π»ΠΎΡΡ Π±Ρ ΠΈΠ·ΠΌΠ΅Π½ΡΡΡ Π²ΡΠ΅ΠΌΡ ΠΎΡ Π²ΡΠ΅ΠΌΠ΅Π½ΠΈ. Π ΠΈΡΠΎΠ³Π΅, ΡΡΡΠ½ΡΠ΅ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΈ Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΡΠ΅ΡΠ΅Π½ΠΈΡ ΡΠΎΠ²Π΅ΡΡΠ΅Π½Π½ΠΎ Π½Π΅ΡΡΡΠ΅ΠΊΡΠΈΠ²Π½Ρ β Π½ΡΠΆΠ½ΠΎ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ ΡΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΈ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΡΠ΅ΠΊΡΠ΅ΡΠΎΠ².
ΠΡΠΎΡΡΠ°Ρ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΠ·Π°ΡΠΈΡ
ΠΠ°ΠΏΠΈΡΠ΅ΠΌ shell-ΡΠΊΡΠΈΠΏΡ, ΠΊΠΎΡΠΎΡΡΠΉ Π·Π°ΠΏΡΡΠΊΠ°Π΅ΡΡΡ ΡΠ°Π· Π² N ΡΠ΅ΠΊΡΠ½Π΄ ΠΈ ΠΏΡΠΎΠ²Π΅ΡΡΠ΅Ρ namespace’Ρ Π½Π° Π½Π°Π»ΠΈΡΠΈΠ΅ ΡΠ΅ΠΊΡΠ΅ΡΠ°, Π° Π΅ΡΠ»ΠΈ ΡΠ΅ΠΊΡΠ΅ΡΠ° Π½Π΅Ρ, ΡΠΎ ΠΎΠ½ ΡΠΎΠ·Π΄Π°ΡΡΡΡ. ΠΠ»ΡΡ ΡΡΠΎΠ³ΠΎ ΡΠ΅ΡΠ΅Π½ΠΈΡ, ΡΡΠΎ ΠΎΠ½ΠΎ Π²ΡΠ³Π»ΡΠ΄ΠΈΡ ΠΊΠ°ΠΊ shell-ΡΠΊΡΠΈΠΏΡ Π² cron’Π΅ β ΠΊΠ»Π°ΡΡΠΈΡΠ΅ΡΠΊΠΈΠΉ ΠΈ Π²ΡΠ΅ΠΌ ΠΏΠΎΠ½ΡΡΠ½ΡΠΉ ΠΏΠΎΠ΄Ρ ΠΎΠ΄. ΠΠΈΠ½ΡΡ ΠΆΠ΅ Π² ΡΠΎΠΌ, ΡΡΠΎ Π² ΠΏΡΠΎΠΌΠ΅ΠΆΡΡΠΊΠ΅ ΠΌΠ΅ΠΆΠ΄Ρ Π΅Π³ΠΎ Π·Π°ΠΏΡΡΠΊΠ°ΠΌΠΈ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ ΡΠΎΠ·Π΄Π°Π½ Π½ΠΎΠ²ΡΠΉ namespace ΠΈ ΠΊΠ°ΠΊΠΎΠ΅-ΡΠΎ Π²ΡΠ΅ΠΌΡ ΠΎΠ½ ΠΎΡΡΠ°Π½Π΅ΡΡΡ Π±Π΅Π· ΡΠ΅ΠΊΡΠ΅ΡΠ°, ΡΡΠΎ ΠΏΡΠΈΠ²Π΅Π΄ΡΡ ΠΊ ΠΎΡΠΈΠ±ΠΊΠ°ΠΌ Π·Π°ΠΏΡΡΠΊΠ° pod’ΠΎΠ².
ΠΠ²ΡΠΎΠΌΠ°ΡΠΈΠ·Π°ΡΠΈΡ Ρ shell-operator
ΠΠ»Ρ ΠΊΠΎΡΡΠ΅ΠΊΡΠ½ΠΎΠΉ ΡΠ°Π±ΠΎΡΡ Π½Π°ΡΠ΅Π³ΠΎ ΡΠΊΡΠΈΠΏΡΠ° ΠΊΠ»Π°ΡΡΠΈΡΠ΅ΡΠΊΠΈΠΉ Π·Π°ΠΏΡΡΠΊ ΠΏΠΎ cron’Ρ Π½ΡΠΆΠ½ΠΎ Π·Π°ΠΌΠ΅Π½ΠΈΡΡ Π½Π° Π·Π°ΠΏΡΡΠΊ ΠΏΡΠΈ ΡΠΎΠ±ΡΡΠΈΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΡ namespace: Π² ΡΠ°ΠΊΠΎΠΌ ΡΠ»ΡΡΠ°Π΅ ΠΌΠΎΠΆΠ½ΠΎ ΡΡΠΏΠ΅ΡΡ ΡΠΎΠ·Π΄Π°ΡΡ ΡΠ΅ΠΊΡΠ΅Ρ Π΄ΠΎ Π΅Π³ΠΎ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ. ΠΠΎΡΠΌΠΎΡΡΠΈΠΌ, ΠΊΠ°ΠΊ ΡΡΠΎ ΡΠ΅Π°Π»ΠΈΠ·ΠΎΠ²Π°ΡΡ Ρ ΠΏΠΎΠΌΠΎΡΡΡ shell-operator.
ΠΠΎ-ΠΏΠ΅ΡΠ²ΡΡ
, ΡΠ°Π·Π±Π΅ΡΡΠΌ ΡΠΊΡΠΈΠΏΡ. Π‘ΠΊΡΠΈΠΏΡΡ Π² ΡΠ΅ΡΠΌΠΈΠ½Π°Ρ
shell-operator Π½Π°Π·ΡΠ²Π°ΡΡΡΡ Ρ
ΡΠΊΠ°ΠΌΠΈ. ΠΠ°ΠΆΠ΄ΡΠΉ Ρ
ΡΠΊ ΠΏΡΠΈ Π·Π°ΠΏΡΡΠΊΠ΅ Ρ ΡΠ»Π°Π³ΠΎΠΌ --config
ΡΠΎΠΎΠ±ΡΠ°Π΅Ρ shell-operator’Ρ ΠΎ ΡΠ²ΠΎΠΈΡ
binding’Π°Ρ
, Ρ.Π΅. ΠΏΠΎ ΠΊΠ°ΠΊΠΈΠΌ ΡΠΎΠ±ΡΡΠΈΡΠΌ Π΅Π³ΠΎ Π½ΡΠΆΠ½ΠΎ Π·Π°ΠΏΡΡΠΊΠ°ΡΡ. Π Π½Π°ΡΠ΅ΠΌ ΡΠ»ΡΡΠ°Π΅ Π²ΠΎΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌΡΡ onKubernetesEvent
:
#!/bin/bash
if [[ $1 == "--config" ]] ; then
cat <<EOF
{
"onKubernetesEvent": [
{ "kind": "namespace",
"event":["add"]
}
]}
EOF
fi
ΠΠ΄Π΅ΡΡ ΠΎΠΏΠΈΡΠ°Π½ΠΎ, ΡΡΠΎ Π½Π°Ρ ΠΈΠ½ΡΠ΅ΡΠ΅ΡΡΡΡ ΡΠΎΠ±ΡΡΠΈΡ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΡ (add
) ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ² ΡΠΈΠΏΠ° namespace
.
Π’Π΅ΠΏΠ΅ΡΡ Π½ΡΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡΡ ΠΊΠΎΠ΄, ΠΊΠΎΡΠΎΡΡΠΉ Π±ΡΠ΄Π΅Ρ Π²ΡΠΏΠΎΠ»Π½ΡΡΡΡΡ ΠΏΡΠΈ Π½Π°ΡΡΡΠΏΠ»Π΅Π½ΠΈΠΈ ΡΠΎΠ±ΡΡΠΈΡ:
#!/bin/bash
if [[ $1 == "--config" ]] ; then
# ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡ
cat <<EOF
{
"onKubernetesEvent": [
{ "kind": "namespace",
"event":["add"]
}
]}
EOF
else
# ΡΠ΅Π°ΠΊΡΠΈΡ:
# ΡΠ·Π½Π°ΡΡ, ΠΊΠ°ΠΊΠΎΠΉ namespace ΠΏΠΎΡΠ²ΠΈΠ»ΡΡ
createdNamespace=$(jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH)
# ΡΠΎΠ·Π΄Π°ΡΡ Π² Π½ΡΠΌ Π½ΡΠΆΠ½ΡΠΉ ΡΠ΅ΠΊΡΠ΅Ρ
kubectl create -n ${createdNamespace} -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
...
data:
...
EOF
fi
ΠΡΠ»ΠΈΡΠ½ΠΎ! ΠΠΎΠ»ΡΡΠΈΠ»ΡΡ Π½Π΅Π±ΠΎΠ»ΡΡΠΎΠΉ, ΠΊΡΠ°ΡΠΈΠ²ΡΠΉ ΡΠΊΡΠΈΠΏΡ. Π§ΡΠΎΠ±Ρ Β«ΠΎΠΆΠΈΠ²ΠΈΡΡΒ» Π΅Π³ΠΎ, ΠΎΡΡΠ°ΡΡΡΡ Π΄Π²Π° ΡΠ°Π³Π°: ΠΏΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΈΡΡ ΠΎΠ±ΡΠ°Π· ΠΈ Π·Π°ΠΏΡΡΡΠΈΡΡ Π΅Π³ΠΎ Π² ΠΊΠ»Π°ΡΡΠ΅ΡΠ΅.
ΠΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΊΠ° ΠΎΠ±ΡΠ°Π·Π° Ρ Ρ ΡΠΊΠΎΠΌ
ΠΡΠ»ΠΈ ΠΏΠΎΡΠΌΠΎΡΡΠ΅ΡΡ Π½Π° ΡΠΊΡΠΈΠΏΡ, ΡΠΎ Π²ΠΈΠ΄Π½ΠΎ, ΡΡΠΎ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡΡΡΡ ΠΊΠΎΠΌΠ°Π½Π΄Ρ kubectl
ΠΈ jq
. ΠΡΠΎ ΠΎΠ·Π½Π°ΡΠ°Π΅Ρ, ΡΡΠΎ Π² ΠΎΠ±ΡΠ°Π·Π΅ Π΄ΠΎΠ»ΠΆΠ½Ρ Π±ΡΡΡ ΡΠ»Π΅Π΄ΡΡΡΠΈΠ΅ Π²Π΅ΡΠΈ: Π½Π°Ρ Ρ
ΡΠΊ, shell-operator, ΠΊΠΎΡΠΎΡΡΠΉ Π±ΡΠ΄Π΅Ρ ΡΠ»Π΅Π΄ΠΈΡΡ Π·Π° ΡΠΎΠ±ΡΡΠΈΡΠΌΠΈ ΠΈ Π·Π°ΠΏΡΡΠΊΠ°ΡΡ Ρ
ΡΠΊ, Π° ΡΠ°ΠΊΠΆΠ΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌΡΠ΅ Ρ
ΡΠΊΠΎΠΌ ΠΊΠΎΠΌΠ°Π½Π΄Ρ (kubectl ΠΈ jq). ΠΠ° hub.docker.com ΡΠΆΠ΅ Π΅ΡΡΡ Π³ΠΎΡΠΎΠ²ΡΠΉ ΠΎΠ±ΡΠ°Π·, Π² ΠΊΠΎΡΠΎΡΠΎΠΌ ΡΠΏΠ°ΠΊΠΎΠ²Π°Π½Ρ shell-operator, kubectl ΠΈ jq. ΠΡΡΠ°ΡΡΡΡ Π΄ΠΎΠ±Π°Π²ΠΈΡΡ Ρ
ΡΠΊ ΠΏΡΠΎΡΡΡΠΌ Dockerfile
:
$ cat Dockerfile
FROM flant/shell-operator:v1.0.0-beta.1-alpine3.9
ADD namespace-hook.sh /hooks
$ docker build -t registry.example.com/my-operator:v1 .
$ docker push registry.example.com/my-operator:v1
ΠΠ°ΠΏΡΡΠΊ Π² ΠΊΠ»Π°ΡΡΠ΅ΡΠ΅
ΠΡΡ ΡΠ°Π· ΠΏΠΎΡΠΌΠΎΡΡΠΈΠΌ Π½Π° Ρ ΡΠΊ ΠΈ Π½Π° ΡΡΠΎΡ ΡΠ°Π· Π²ΡΠΏΠΈΡΠ΅ΠΌ, ΠΊΠ°ΠΊΠΈΠ΅ Π΄Π΅ΠΉΡΡΠ²ΠΈΡ ΠΈ Ρ ΠΊΠ°ΠΊΠΈΠΌΠΈ ΠΎΠ±ΡΠ΅ΠΊΡΠ°ΠΌΠΈ ΠΎΠ½ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ Π² ΠΊΠ»Π°ΡΡΠ΅ΡΠ΅:
- ΠΏΠΎΠ΄ΠΏΠΈΡΡΠ²Π°Π΅ΡΡΡ Π½Π° ΡΠΎΠ±ΡΡΠΈΡ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ namespace’ΠΎΠ²;
- ΡΠΎΠ·Π΄Π°ΡΡ ΡΠ΅ΠΊΡΠ΅Ρ Π² namespace’Π°Ρ , ΠΎΡΠ»ΠΈΡΠ½ΡΡ ΠΎΡ ΡΠΎΠ³ΠΎ, Π³Π΄Π΅ Π·Π°ΠΏΡΡΠ΅Π½.
ΠΠΎΠ»ΡΡΠ°Π΅ΡΡΡ, ΡΡΠΎ pod, Π² ΠΊΠΎΡΠΎΡΠΎΠΌ Π±ΡΠ΄Π΅Ρ Π·Π°ΠΏΡΡΠ΅Π½ Π½Π°Ρ ΠΎΠ±ΡΠ°Π·, Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΈΠΌΠ΅ΡΡ ΡΠ°Π·ΡΠ΅ΡΠ΅Π½ΠΈΡ Π½Π° ΡΡΠΈ Π΄Π΅ΠΉΡΡΠ²ΠΈΡ. ΠΡΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°ΡΡ Ρ ΠΏΠΎΠΌΠΎΡΡΡ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΡΠ²ΠΎΠ΅Π³ΠΎ ServiceAccount. Π Π°Π·ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ Π½ΡΠΆΠ½ΠΎ Π΄Π΅Π»Π°ΡΡ Π² Π²ΠΈΠ΄Π΅ ClusterRole ΠΈ ClusterRoleBinding, Ρ.ΠΊ. Π½Π°ΠΌ ΠΈΠ½ΡΠ΅ΡΠ΅ΡΠ½Ρ ΠΎΠ±ΡΠ΅ΠΊΡΡ ΡΠΎ Π²ΡΠ΅Π³ΠΎ ΠΊΠ»Π°ΡΡΠ΅ΡΠ°.
ΠΡΠΎΠ³ΠΎΠ²ΠΎΠ΅ ΠΎΠΏΠΈΡΠ°Π½ΠΈΠ΅ Π² YAML ΠΏΠΎΠ»ΡΡΠΈΡΡΡ ΠΏΡΠΈΠΌΠ΅ΡΠ½ΠΎ ΡΠ°ΠΊΠΈΠΌ:
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: monitor-namespaces-acc
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: monitor-namespaces
rules:
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "watch", "list"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "create", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: monitor-namespaces
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: monitor-namespaces
subjects:
- kind: ServiceAccount
name: monitor-namespaces-acc
namespace: example-monitor-namespaces
ΠΠ°ΠΏΡΡΡΠΈΡΡ ΡΠΎΠ±ΡΠ°Π½Π½ΡΠΉ ΠΎΠ±ΡΠ°Π· ΠΌΠΎΠΆΠ½ΠΎ Π² Π²ΠΈΠ΄Π΅ ΠΏΡΠΎΡΡΠΎΠ³ΠΎ Deployment:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: my-operator
spec:
template:
spec:
containers:
- name: my-operator
image: registry.example.com/my-operator:v1
serviceAccountName: monitor-namespaces-acc
ΠΠ»Ρ ΡΠ΄ΠΎΠ±ΡΡΠ²Π° ΡΠΎΠ·Π΄Π°ΡΡΡΡ ΠΎΡΠ΄Π΅Π»ΡΠ½ΡΠΉ namespace, Π³Π΄Π΅ Π±ΡΠ΄Π΅Ρ Π·Π°ΠΏΡΡΠΊΠ°ΡΡΡΡ shell-operator ΠΈ ΠΏΡΠΈΠΌΠ΅Π½ΡΡΡΡΡ ΡΠΎΠ·Π΄Π°Π½Π½ΡΠ΅ ΠΌΠ°Π½ΠΈΡΠ΅ΡΡΡ:
$ kubectl create ns example-monitor-namespaces
$ kubectl -n example-monitor-namespaces apply -f rbac.yaml
$ kubectl -n example-monitor-namespaces apply -f deployment.yaml
ΠΠ° ΡΡΠΎΠΌ Π²ΡΡ: shell-operator Π·Π°ΠΏΡΡΡΠΈΡΡΡ, ΠΏΠΎΠ΄ΠΏΠΈΡΠ΅ΡΡΡ Π½Π° ΡΠΎΠ±ΡΡΠΈΡ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ namespace’ΠΎΠ² ΠΈ Π±ΡΠ΄Π΅Ρ Π·Π°ΠΏΡΡΠΊΠ°ΡΡ Ρ ΡΠΊ, ΠΊΠΎΠ³Π΄Π° Π½ΡΠΆΠ½ΠΎ.
Π’Π°ΠΊΠΈΠΌ ΠΎΠ±ΡΠ°Π·ΠΎΠΌ, ΠΏΡΠΎΡΡΠΎΠΉ shell-ΡΠΊΡΠΈΠΏΡ ΠΏΡΠ΅Π²ΡΠ°ΡΠΈΠ»ΡΡ Π² Π½Π°ΡΡΠΎΡΡΠΈΠΉ operator Π΄Π»Ρ Kubernetes ΠΈ ΡΠ°Π±ΠΎΡΠ°Π΅Ρ ΠΊΠ°ΠΊ ΡΠΎΡΡΠ°Π²Π½Π°Ρ ΡΠ°ΡΡΡ ΠΊΠ»Π°ΡΡΠ΅ΡΠ°. Π Π²ΡΡ ΡΡΠΎ β Π±Π΅Π· ΡΠ»ΠΎΠΆΠ½ΠΎΠ³ΠΎ ΠΏΡΠΎΡΠ΅ΡΡΠ° ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠΈ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΠΎΠ² Π½Π° Golang:
ΠΡΡΡ ΠΈ Π΄ΡΡΠ³Π°Ρ ΠΈΠ»Π»ΡΡΡΡΠ°ΡΠΈΡ Π½Π° ΡΡΠΎΡ ΡΡΡΡβ¦
ΠΡ ΡΠΌΡΡΠ» ΠΌΡ ΡΠ°ΡΠΊΡΠΎΠ΅ΠΌ ΠΏΠΎΠ΄ΡΠΎΠ±Π½Π΅Π΅ Π² ΠΎΠ΄Π½ΠΎΠΉ ΠΈΠ· ΡΠ»Π΅Π΄ΡΡΡΠΈΡ
ΠΏΡΠ±Π»ΠΈΠΊΠ°ΡΠΈΠΉ.
Π€ΠΈΠ»ΡΡΡΠ°ΡΠΈΡ
Π‘Π»Π΅ΠΆΠ΅Π½ΠΈΠ΅ Π·Π° ΠΎΠ±ΡΠ΅ΠΊΡΠ°ΠΌΠΈ β ΡΡΠΎ Ρ ΠΎΡΠΎΡΠΎ, Π½ΠΎ Π·Π°ΡΠ°ΡΡΡΡ Π±ΡΠ²Π°Π΅Ρ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎΡΡΡ ΡΠ΅Π°Π³ΠΈΡΠΎΠ²Π°ΡΡ Π½Π° ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΊΠ°ΠΊΠΈΡ -ΡΠΎ ΡΠ²ΠΎΠΉΡΡΠ² ΠΎΠ±ΡΠ΅ΠΊΡΠ°, Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, Π½Π° ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²Π° ΡΠ΅ΠΏΠ»ΠΈΠΊ Π² DeploymentβΠ΅ ΠΈΠ»ΠΈ Π½Π° ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Π»Π΅ΠΉΠ±Π»ΠΎΠ² ΠΎΠ±ΡΠ΅ΠΊΡΠ°.
ΠΠΎΠ³Π΄Π° ΠΏΡΠΈΡ
ΠΎΠ΄ΠΈΡ ΡΠΎΠ±ΡΡΠΈΠ΅, shell-operator ΠΏΠΎΠ»ΡΡΠ°Π΅Ρ JSON-ΠΌΠ°Π½ΠΈΡΠ΅ΡΡ ΠΎΠ±ΡΠ΅ΠΊΡΠ°. ΠΠΎΠΆΠ½ΠΎ Π²ΡΠ΄Π΅Π»ΠΈΡΡ Π² ΡΡΠΎΠΌ JSON ΠΈΠ½ΡΠ΅ΡΠ΅ΡΡΡΡΠΈΠ΅ Π½Π°Ρ ΡΠ²ΠΎΠΉΡΡΠ²Π° ΠΈ Π·Π°ΠΏΡΡΠΊΠ°ΡΡ Ρ
ΡΠΊ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΡΠΈ ΠΈΡ
ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡΡ
. ΠΠ»Ρ ΡΡΠΎΠ³ΠΎ ΠΏΡΠ΅Π΄ΡΡΠΌΠΎΡΡΠ΅Π½ΠΎ ΠΏΠΎΠ»Π΅ jqFilter
, Π³Π΄Π΅ Π½ΡΠΆΠ½ΠΎ ΡΠΊΠ°Π·Π°ΡΡ Π²ΡΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ jq, ΠΊΠΎΡΠΎΡΠΎΠ΅ Π±ΡΠ΄Π΅Ρ ΠΏΡΠΈΠΌΠ΅Π½Π΅Π½ΠΎ ΠΊ JSON-ΠΌΠ°Π½ΠΈΡΠ΅ΡΡΡ.
ΠΠ°ΠΏΡΠΈΠΌΠ΅Ρ, ΡΡΠΎΠ±Ρ ΡΠ΅Π°Π³ΠΈΡΠΎΠ²Π°ΡΡ Π½Π° ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Π»Π΅ΠΉΠ±Π»ΠΎΠ² Ρ ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠ² Deployment, Π½ΡΠΆΠ½ΠΎ ΠΎΡΡΠΈΠ»ΡΡΡΠΎΠ²Π°ΡΡ ΠΏΠΎΠ»Π΅ labels
ΠΈΠ· ΠΏΠΎΠ»Ρ metadata
. ΠΠΎΠ½ΡΠΈΠ³ Π±ΡΠ΄Π΅Ρ ΡΠ°ΠΊΠΎΠΉ:
cat <<EOF
{
"onKubernetesEvent": [
{ "kind": "deployment",
"event":["update"],
"jqFilter": ".metadata.labels"
}
]}
EOF
ΠΡΠΎ Π²ΡΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ Π² jqFilter ΠΏΡΠ΅Π²ΡΠ°ΡΠ°Π΅Ρ Π΄Π»ΠΈΠ½Π½ΡΠΉ JSON-ΠΌΠ°Π½ΠΈΡΠ΅ΡΡΠ° Deployment’Π° Π² ΠΊΠΎΡΠΎΡΠΊΠΈΠΉ JSON Ρ Π»Π΅ΠΉΠ±Π»Π°ΠΌΠΈ:
shell-operator Π±ΡΠ΄Π΅Ρ Π·Π°ΠΏΡΡΠΊΠ°ΡΡ Ρ
ΡΠΊ ΡΠΎΠ»ΡΠΊΠΎ Π² ΡΠ΅Ρ
ΡΠ»ΡΡΠ°ΡΡ
, ΠΊΠΎΠ³Π΄Π° ΠΈΠ·ΠΌΠ΅Π½ΠΈΡΡΡ ΡΡΠΎΡ ΠΊΠΎΡΠΎΡΠΊΠΈΠΉ JSON, Π° ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ Π² Π΄ΡΡΠ³ΠΈΡ
ΡΠ²ΠΎΠΉΡΡΠ²Π°Ρ
Π±ΡΠ΄ΡΡ ΠΈΠ³Π½ΠΎΡΠΈΡΠΎΠ²Π°ΡΡΡΡ.
ΠΠΎΠ½ΡΠ΅ΠΊΡΡ Π·Π°ΠΏΡΡΠΊΠ° Ρ ΡΠΊΠ°
ΠΠΎΠ½ΡΠΈΠ³ Ρ ΡΠΊΠ° ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΡΠΊΠ°Π·Π°ΡΡ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ Π²Π°ΡΠΈΠ°Π½ΡΠΎΠ² ΡΠΎΠ±ΡΡΠΈΠΉ β Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, 2 Π²Π°ΡΠΈΠ°Π½ΡΠ° Π΄Π»Ρ ΡΠΎΠ±ΡΡΠΈΠΉ ΠΎΡ Kubernetes ΠΈ 2 ΡΠ°ΡΠΏΠΈΡΠ°Π½ΠΈΡ:
{"onKubernetesEvent":[
{"name":"OnCreatePod",
"kind": "pod",
"event":["add"]
},
{"name":"OnModifiedNamespace",
"kind": "namespace",
"event":["update"],
"jqFilter": ".metadata.labels"
}
],
"schedule": [
{ "name":"every 10 min",
"crontab":"* */10 * * * *"
}, {"name":"on Mondays at 12:10",
"crontab": "* 10 12 * * 1"
]}
ΠΠ΅Π±ΠΎΠ»ΡΡΠΎΠ΅ ΠΎΡΡΡΡΠΏΠ»Π΅Π½ΠΈΠ΅: Π΄Π°, shell-operator ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅Ρ Π·Π°ΠΏΡΡΠΊ ΡΠΊΡΠΈΠΏΡΠΎΠ² Π² ΡΡΠΈΠ»Π΅ crontab. ΠΠΎΠ»Π΅Π΅ ΠΏΠΎΠ΄ΡΠΎΠ±Π½ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΈΡΠ°ΡΡ Π²
Π§ΡΠΎΠ±Ρ ΡΠ°Π·Π»ΠΈΡΠ°ΡΡ, Π² ΡΠ²ΡΠ·ΠΈ Ρ ΡΠ΅ΠΌ Π±ΡΠ» Π·Π°ΠΏΡΡΠ΅Π½ Ρ
ΡΠΊ, shell-operator ΡΠΎΠ·Π΄Π°ΡΡ Π²ΡΠ΅ΠΌΠ΅Π½Π½ΡΠΉ ΡΠ°ΠΉΠ» ΠΈ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΡ Ρ
ΡΠΊΡ ΠΏΡΡΡ ΠΊ Π½Π΅ΠΌΡ Π² ΠΏΠ΅ΡΠ΅ΠΌΠ΅Π½Π½ΠΎΠΉ BINDING_CONTEXT_TYPE
. Π ΡΠ°ΠΉΠ»Π΅ Π»Π΅ΠΆΠΈΡ JSON-ΠΎΠΏΠΈΡΠ°Π½ΠΈΠ΅ ΠΏΡΠΈΡΠΈΠ½Ρ Π·Π°ΠΏΡΡΠΊΠ° Ρ
ΡΠΊΠ°. ΠΠ°ΠΏΡΠΈΠΌΠ΅Ρ, ΠΊΠ°ΠΆΠ΄ΡΠ΅ 10 ΠΌΠΈΠ½ΡΡ Ρ
ΡΠΊ Π±ΡΠ΄Π΅Ρ Π·Π°ΠΏΡΡΠΊΠ°ΡΡΡΡ Ρ ΡΠ°ΠΊΠΈΠΌ ΡΠΎΠ΄Π΅ΡΠΆΠΈΠΌΡΠΌ:
[{ "binding": "every 10 min"}]
β¦ Π° Π² ΠΏΠΎΠ½Π΅Π΄Π΅Π»ΡΠ½ΠΈΠΊ Π·Π°ΠΏΡΡΡΠΈΡΡΡ Ρ ΡΠ°ΠΊΠΈΠΌ:
[{ "binding": "every 10 min"}, { "binding": "on Mondays at 12:10"}]
ΠΠ»Ρ onKubernetesEvent
ΡΡΠ°Π±Π°ΡΡΠ²Π°Π½ΠΈΠΉ JSON Π±ΡΠ΄Π΅Ρ ΠΏΠΎΠ±ΠΎΠ»ΡΡΠ΅, Ρ.ΠΊ. ΠΎΠ½ΠΎ ΡΠΎΠ΄Π΅ΡΠΆΠΈΡ ΠΎΠΏΠΈΡΠ°Π½ΠΈΠ΅ ΠΎΠ±ΡΠ΅ΠΊΡΠ°:
[
{
"binding": "onCreatePod",
"resourceEvent": "add",
"resourceKind": "pod",
"resourceName": "foo",
"resourceNamespace": "bar"
}
]
Π‘ΠΎΠ΄Π΅ΡΠΆΠΈΠΌΠΎΠ΅ ΠΏΠΎΠ»Π΅ΠΉ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ½ΡΡΡ ΠΈΠ· ΠΈΡ
ΠΈΠΌΡΠ½, Π° Π±ΠΎΠ»Π΅Π΅ ΠΏΠΎΠ΄ΡΠΎΠ±Π½ΠΎ β ΠΏΡΠΎΡΠ΅ΡΡΡ Π² resourceName
Ρ ΠΏΠΎΠΌΠΎΡΡΡ jq ΡΠΆΠ΅ Π±ΡΠ» ΠΏΠΎΠΊΠ°Π·Π°Π½ Π² Ρ
ΡΠΊΠ΅, ΠΊΠΎΡΠΎΡΡΠΉ ΡΠΈΡΠ°ΠΆΠΈΡΡΠ΅Ρ ΡΠ΅ΠΊΡΠ΅ΡΡ:
jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH
ΠΠ½Π°Π»ΠΎΠ³ΠΈΡΠ½ΡΠΌ ΠΎΠ±ΡΠ°Π·ΠΎΠΌ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ»ΡΡΠ°ΡΡ ΠΈ ΠΎΡΡΠ°Π»ΡΠ½ΡΠ΅ ΠΏΠΎΠ»Ρ.
Π§ΡΠΎ Π΄Π°Π»ΡΡΠ΅?
Π ΡΠ΅ΠΏΠΎΠ·ΠΈΡΠΎΡΠΈΠΈ ΠΏΡΠΎΠ΅ΠΊΡΠ°, Π²
ΠΡΡΡ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΊΠ° ΡΠ±ΠΎΡΠ° ΠΌΠ΅ΡΡΠΈΠΊ Ρ ΠΏΠΎΠΌΠΎΡΡΡ Prometheus β ΠΎ Π΄ΠΎΡΡΡΠΏΠ½ΡΡ
ΠΌΠ΅ΡΡΠΈΠΊΠ°Ρ
Π½Π°ΠΏΠΈΡΠ°Π½ΠΎ Π² ΡΠ°Π·Π΄Π΅Π»Π΅
ΠΠ°ΠΊ Π»Π΅Π³ΠΊΠΎ Π΄ΠΎΠ³Π°Π΄Π°ΡΡΡΡ shell-operator Π½Π°ΠΏΠΈΡΠ°Π½ Π½Π° Go ΠΈ ΡΠ°ΡΠΏΡΠΎΡΡΡΠ°Π½ΡΠ΅ΡΡΡ ΠΏΠΎΠ΄ Open Source-Π»ΠΈΡΠ΅Π½Π·ΠΈΠ΅ΠΉ (Apache 2.0). ΠΡ Π±ΡΠ΄Π΅ΠΌ Π±Π»Π°Π³ΠΎΠ΄Π°ΡΠ½Ρ Π»ΡΠ±ΠΎΠΉ ΠΏΠΎΠΌΠΎΡΠΈ ΠΏΠΎ ΡΠ°Π·Π²ΠΈΡΠΈΡ
ΠΡΠΈΠΎΡΠΊΡΡΠ²Π°Ρ Π·Π°Π²Π΅ΡΡ ΡΠ°ΠΉΠ½Ρ, ΡΠ°ΠΊΠΆΠ΅ ΡΠΎΠΎΠ±ΡΠΈΠΌ, ΡΡΠΎ shell-operator β ΡΡΠΎ Π½Π΅Π±ΠΎΠ»ΡΡΠ°Ρ ΡΠ°ΡΡΡ Π½Π°ΡΠ΅ΠΉ ΡΠΈΡΡΠ΅ΠΌΡ, ΠΊΠΎΡΠΎΡΠ°Ρ ΡΠΌΠ΅Π΅Ρ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°ΡΡ Π² Π°ΠΊΡΡΠ°Π»ΡΠ½ΠΎΠΌ ΡΠΎΡΡΠΎΡΠ½ΠΈΠΈ Π΄ΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ, ΡΡΡΠ°Π½ΠΎΠ²Π»Π΅Π½Π½ΡΠ΅ Π² ΠΊΠ»Π°ΡΡΠ΅ΡΠ΅ Kubernetes, ΠΈ ΠΎΡΡΡΠ΅ΡΡΠ²Π»ΡΠ΅Ρ ΡΠ°Π·Π»ΠΈΡΠ½ΡΠ΅ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΠ΅ Π΄Π΅ΠΉΡΡΠ²ΠΈΡ. ΠΠΎΠ΄ΡΠΎΠ±Π½Π΅Π΅ ΠΎΠ± ΡΡΠΎΠΉ ΡΠΈΡΡΠ΅ΠΌΠ΅ ΠΌΡ
Π£ Π½Π°Ρ Π΅ΡΡΡ ΠΏΠ»Π°Π½ ΠΎΡΠΊΡΡΡΡ ΠΈ ΠΎΡΡΠ°Π»ΡΠ½ΡΠ΅ ΡΠ°ΡΡΠΈ ΡΡΠΎΠΉ ΡΠΈΡΡΠ΅ΠΌΡ: addon-operator ΠΈ Π½Π°ΡΡ ΠΊΠΎΠ»Π»Π΅ΠΊΡΠΈΡ Ρ
ΡΠΊΠΎΠ² ΠΈ ΠΌΠΎΠ΄ΡΠ»Π΅ΠΉ. ΠΡΡΠ°ΡΠΈ, addon-operator ΡΠΆΠ΅
Stay tuned!
P.S.
Π§ΠΈΡΠ°ΠΉΡΠ΅ ΡΠ°ΠΊΠΆΠ΅ Π² Π½Π°ΡΠ΅ΠΌ Π±Π»ΠΎΠ³Π΅:
- Β«
ΠΠΏΠ΅ΡΠ°ΡΠΎΡΡ Π΄Π»Ρ Kubernetes: ΠΊΠ°ΠΊ Π·Π°ΠΏΡΡΠΊΠ°ΡΡ stateful-ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ Β»; - Β«
ΠΠΈΡΠ΅ΠΌ ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡΠ° Π΄Π»Ρ Kubernetes Π½Π° Golang Β»; - Β«
ΠΡΠ΅Π΄ΡΡΠ°Π²Π»ΡΠ΅ΠΌ Π½ΠΎΠ²ΡΠΉ ΠΏΠ»Π°Π³ΠΈΠ½ Π΄Π»Ρ Grafana β Statusmap panel Β»; - Β«
ΠΡΠ΅Π΄ΡΡΠ°Π²Π»ΡΠ΅ΠΌ loghouse β Open Source-ΡΠΈΡΡΠ΅ΠΌΡ Π΄Π»Ρ ΡΠ°Π±ΠΎΡΡ Ρ Π»ΠΎΠ³Π°ΠΌΠΈ Π² Kubernetes Β»; - Β«
ΠΡΠΈΡΠΈΠ°Π»ΡΠ½ΠΎ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»ΡΠ΅ΠΌ dapp β DevOps-ΡΡΠΈΠ»ΠΈΡΡ Π΄Π»Ρ ΡΠΎΠΏΡΠΎΠ²ΠΎΠΆΠ΄Π΅Π½ΠΈΡ CI/CD Β».
ΠΡΡΠΎΡΠ½ΠΈΠΊ: habr.com