This commit is contained in:
alessandro
2026-07-17 09:42:52 +02:00
commit 20d506407a
93 changed files with 14526 additions and 0 deletions

118
add-on/CephCsi.txt Normal file
View File

@@ -0,0 +1,118 @@
kubectl create namespace ceph-csi
git clone https://github.com/ceph/ceph-csi.git
cd ceph-csi
git checkout v3.15.0
# move to rbd chart.
cd charts/ceph-csi-rbd
cat <<EOF > ceph-csi-rbd-values.yaml
csiConfig:
- clusterID: "004ee854-86cc-4ddc-b7d6-75e4fe962296"
monitors:
- "172.20.1.33:6789"
- "172.20.1.34:6789"
- "172.20.1.35:6789"
provisioner:
name: provisioner
replicaCount: 2
EOF
helm install --namespace ceph-csi ceph-csi --values ceph-csi-rbd-values.yaml ./
Examples on how to configure a storage class and start using the driver are here:
https://github.com/ceph/ceph-csi/tree/devel/examples/rbd
echo "kubernetes" | tr -d '\n' | base64
a3ViZXJuZXRlcw==
cat > ceph-admin-secret.yaml << EOF
apiVersion: v1
kind: Secret
metadata:
name: csi-rbd-secret
namespace: default
stringData:
userID: kubernetes
userKey: AQD2zo5pm8aZIRAAPzWS+dROeX7iJtv5EukfKA==
EOF
# create a secret for admin user.
kubectl apply -f ceph-admin-secret.yaml
----- Create StorageClass ------
cat > ceph-rbd-sc.yaml <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ceph-rbd-sc
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: rbd.csi.ceph.com
parameters:
clusterID: 004ee854-86cc-4ddc-b7d6-75e4fe962296
pool: k8s-rbd
imageFeatures: layering
csi.storage.k8s.io/provisioner-secret-name: csi-rbd-secret
csi.storage.k8s.io/provisioner-secret-namespace: default
csi.storage.k8s.io/controller-expand-secret-name: csi-rbd-secret
csi.storage.k8s.io/controller-expand-secret-namespace: default
csi.storage.k8s.io/node-stage-secret-name: csi-rbd-secret
csi.storage.k8s.io/node-stage-secret-namespace: default
reclaimPolicy: Delete
allowVolumeExpansion: true
mountOptions:
- discard
EOF
# create a storage class
kubectl apply -f ceph-rbd-sc.yaml;
--- test
cat <<EOF > create-ceph-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: raw-block-pvc
spec:
accessModes:
- ReadWriteOnce
volumeMode: Block
resources:
requests:
storage: 1Gi
storageClassName: csi-rbd-sc
EOF
# create pvc
kubectl apply -f create-ceph-pvc.yaml
cat <<EOF > create-pod-with-pvc.yaml
apiVersion: v1
kind: Pod
metadata:
name: ceph-pod-pvc
spec:
containers:
- name: ceph-pod-pvc
image: busybox
command: ["sleep", "infinity"]
volumeMounts:
- mountPath: /mnt/ceph_rbd
name: volume
volumes:
- name: volume
persistentVolumeClaim:
claimName: raw-block-pvc
EOF
# create pod
kubectl apply -f create-pod-with-pvc.yaml

122
add-on/CephCsi_install.txt Normal file
View File

@@ -0,0 +1,122 @@
cat <<EOF > csi-config-map.yaml
---
apiVersion: v1
kind: ConfigMap
data:
config.json: |-
[
{
"clusterID": "004ee854-86cc-4ddc-b7d6-75e4fe962296",
"monitors": [
"72.20.1.33:6789",
"72.20.1.34:6789",
"72.20.1.35:6789"
]
}
]
metadata:
name: ceph-csi-config
EOF
kubectl apply -f csi-config-map.yaml
cat <<EOF > csi-kms-config-map.yaml
---
apiVersion: v1
kind: ConfigMap
data:
config.json: |-
{}
metadata:
name: ceph-csi-encryption-kms-config
EOF
kubectl apply -f csi-kms-config-map.yaml
cat <<EOF > ceph-config-map.yaml
---
apiVersion: v1
kind: ConfigMap
data:
ceph.conf: |
[global]
auth_cluster_required = cephx
auth_service_required = cephx
auth_client_required = cephx
# keyring is a required key and its value should be empty
keyring: |
metadata:
name: ceph-config
EOF
kubectl apply -f ceph-config-map.yaml
cat <<EOF > csi-rbd-secret.yaml
---
apiVersion: v1
kind: Secret
metadata:
name: csi-rbd-secret
namespace: default
stringData:
userID: kubernetes
userKey: AQD2zo5pm8aZIRAAPzWS+dROeX7iJtv5EukfKA==
EOF
kubectl apply -f https://raw.githubusercontent.com/ceph/ceph-csi/master/deploy/rbd/kubernetes/csi-provisioner-rbac.yaml
kubectl apply -f https://raw.githubusercontent.com/ceph/ceph-csi/master/deploy/rbd/kubernetes/csi-nodeplugin-rbac.yaml
wget https://raw.githubusercontent.com/ceph/ceph-csi/master/deploy/rbd/kubernetes/csi-rbdplugin-provisioner.yaml
kubectl apply -f csi-rbdplugin-provisioner.yaml
wget https://raw.githubusercontent.com/ceph/ceph-csi/master/deploy/rbd/kubernetes/csi-rbdplugin.yaml
kubectl apply -f csi-rbdplugin.yaml
------- TEST-----
cat <<EOF > csi-rbd-sc.yaml
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-rbd-sc
provisioner: rbd.csi.ceph.com
parameters:
clusterID: 004ee854-86cc-4ddc-b7d6-75e4fe962296
pool: k8s-rbd
imageFeatures: layering
csi.storage.k8s.io/provisioner-secret-name: csi-rbd-secret
csi.storage.k8s.io/provisioner-secret-namespace: default
csi.storage.k8s.io/controller-expand-secret-name: csi-rbd-secret
csi.storage.k8s.io/controller-expand-secret-namespace: default
csi.storage.k8s.io/node-stage-secret-name: csi-rbd-secret
csi.storage.k8s.io/node-stage-secret-namespace: default
reclaimPolicy: Delete
allowVolumeExpansion: true
mountOptions:
- discard
EOF
kubectl apply -f csi-rbd-sc.yaml
cat <<EOF > raw-block-pvc.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: raw-block-pvc
spec:
accessModes:
- ReadWriteOnce
volumeMode: Block
resources:
requests:
storage: 1Gi
storageClassName: csi-rbd-sc
EOF
kubectl apply -f raw-block-pvc.yaml

View File

@@ -0,0 +1,276 @@
Cloudside:
wget https://github.com/kubeedge/kubeedge/releases/download/v1.17.0/keadm-v1.17.0-linux-amd64.tar.gz
tar -zxvf keadm-v1.17.0-linux-amd64.tar.gz
cp keadm-v1.17.0-linux-amd64/keadm/keadm /usr/local/bin/keadm
keadm init --advertise-address="89.105.78.161" --kubeedge-version=v1.22.0 --kube-config=/root/.kube/config
keadm manifest generate --advertise-address="89.105.78.161" --kube-config=/root/.kube/config > kubeedge-cloudcore.yaml
patch:
cloudcore.yaml: |
apiVersion: cloudcore.config.kubeedge.io/v1alpha2
commonConfig:
monitorServer:
bindAddress: 127.0.0.1:9091
tunnelPort: 10354
featureGates:
requireAuthorization: false
kind: CloudCore
kubectl apply -f kubeedge-cloudcore.yaml -n kubeedge
kubectl apply -f edgenodeport.yaml -n kubeedge
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
Edge Side:
export KUBEEDGE_VERSION=v1.22.0
export CLOUD_MASTER_IP=34.132.113.155
export EDGE_NODE_NAME=edge-node-02
Step 1 : Download & unpack containerd package
Containerd versions can be found in this location : https://github.com/containerd/containerd/releases
Download :
wget https://github.com/containerd/containerd/releases/download/v1.6.14/containerd-1.6.14-linux-amd64.tar.gz
Unpack :
sudo tar Cxzvf /usr/local containerd-1.6.14-linux-amd64.tar.gz
Step 2 : Install runc
Runc is a standardized runtime for spawning and running containers on Linux according to the OCI specification
wget https://github.com/opencontainers/runc/releases/download/v1.1.3/runc.amd64
sudo install -m 755 runc.amd64 /usr/local/sbin/runc
Step 3: Download and install CNI plugins :
wget https://github.com/containernetworking/plugins/releases/download/v1.1.1/cni-plugins-linux-amd64-v1.1.1.tgz
sudo mkdir -p /opt/cni/bin
sudo tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v1.1.1.tgz
Step 4: Configure containerd
Create a containerd directory for the configuration file
config.toml is the default configuration file for containerd
Enable systemd group . Use sed command to change the parameter in config.toml instead of using vi editor
Convert containerd into service
sudo mkdir /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
sudo sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml
sudo curl -L https://raw.githubusercontent.com/containerd/containerd/main/containerd.service -o /etc/systemd/system/containerd.service
Step 4.1
remove SystemdCgroup = true line from /etc/containerd/config.toml.
Step 4.2
mkdir -p /etc/cni/net.d/
$ cat >/etc/cni/net.d/10-containerd-net.conflist <<EOF
{
"cniVersion": "1.0.0",
"name": "containerd-net",
"plugins": [
{
"type": "bridge",
"bridge": "cni0",
"isGateway": true,
"ipMasq": true,
"promiscMode": true,
"ipam": {
"type": "host-local",
"ranges": [
[{
"subnet": "10.88.0.0/16"
}],
[{
"subnet": "2001:db8:4860::/64"
}]
],
"routes": [
{ "dst": "0.0.0.0/0" },
{ "dst": "::/0" }
]
}
},
{
"type": "portmap",
"capabilities": {"portMappings": true}
}
]
}
EOF
Step 5: Start containerd service
sudo systemctl daemon-reload
sudo systemctl enable --now containerd
sudo systemctl status containerd
step 6: install crictl
VERSION="v1.35.0" # check latest version in /releases page
wget https://github.com/kubernetes-sigs/cri-tools/releases/download/$VERSION/crictl-$VERSION-linux-amd64.tar.gz
sudo tar zxvf crictl-$VERSION-linux-amd64.tar.gz -C /usr/local/bin
rm -f crictl-$VERSION-linux-amd64.tar.gz
edge-cleanup.sh:
#!/bin/bash
set -euo pipefail
echo "==== EDGE NODE CLEANUP START ===="
DATE=$(date)
echo "Timestamp: $DATE"
# -------------------------------
# 1. Kill processi orfani (safe)
# -------------------------------
echo "[1] Checking orphan processes..."
ORPHANS=$(ps -eo pid,ppid,cmd | awk '$2 == 1 {print $1}')
for PID in $ORPHANS; do
if [ "$PID" != "1" ]; then
echo "Killing orphan PID: $PID"
kill -9 "$PID" 2>/dev/null || true
fi
done
# -------------------------------
# 2. Cleanup containerd (safe)
# -------------------------------
echo "[2] Cleaning containerd..."
if command -v crictl &> /dev/null; then
echo "Using crictl..."
# rimuove solo container stopped
crictl ps -a --state Exited -q | xargs -r crictl rm || true
# rimuove pod sandbox non più validi
crictl pods --state NotReady -q | xargs -r crictl rmp || true
# pulizia immagini dangling (SAFE)
crictl rmi --prune || true
else
echo "crictl not found, skipping..."
fi
# -------------------------------
# 3. Restart containerd
# -------------------------------
echo "[3] Restarting containerd..."
systemctl restart containerd
# -------------------------------
# 4. Cleanup kubelet (soft)
# -------------------------------
echo "[4] Cleaning kubelet state (soft)..."
# Rimuove solo pod non più esistenti
find /var/lib/kubelet/pods -mindepth 1 -maxdepth 1 -type d -mtime +1 -exec rm -rf {} + || true
# -------------------------------
# 5. Restart kube services
# -------------------------------
echo "[5] Restarting kubelet + edgecore..."
systemctl restart kubelet || true
systemctl restart edgecore || true
# -------------------------------
# 6. Verifica connessione CloudCore
# -------------------------------
echo "[6] Checking connectivity to CloudCore..."
CLOUD_IP="89.105.78.161"
PORT="10002"
if timeout 5 bash -c "</dev/tcp/$CLOUD_IP/$PORT"; then
echo "Cloud reachable"
else
echo "WARNING: Cloud NOT reachable"
fi
# -------------------------------
# 7. Verifica porte MQTT locali
# -------------------------------
echo "[7] Checking MQTT port..."
ss -tulnp | grep 1883 || echo "WARNING: Mosquitto not listening"
echo "==== EDGE NODE CLEANUP DONE ===="
/etc/systemd/system/edge-cleanup.service:
[Unit]
Description=Edge Node Cleanup
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/edge-cleanup.sh
RemainAfterExit=true
[Install]
WantedBy=multi-user.target
chmod +x /usr/local/bin/edge-cleanup.sh
systemctl daemon-reload
systemctl enable edge-cleanup
export KUBEEDGE_VERSION=v1.22.0
export CLOUD_MASTER_IP=194.110.57.153
export EDGE_NODE_NAME=edge-node-02
curl -L https://github.com/kubeedge/kubeedge/releases/download/${KUBEEDGE_VERSION}/keadm-${KUBEEDGE_VERSION}-linux-amd64.tar.gz | tar -xz
sudo mv keadm-${KUBEEDGE_VERSION}-linux-amd64/keadm/keadm /usr/local/bin/
sudo keadm join \
--cloudcore-ipport=${CLOUD_MASTER_IP}:10000 \
--edgenode-name=${EDGE_NODE_NAME} \
--token=f871f93cffd630c906bf381dae4496544a111075071abfec060e2db4ab417b6e.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NzUyOTM2NjJ9.xvMdgApjtPDpPm-GShmR6ghjBgvFTJsJf6JTJLeSK08 \
--kubeedge-version=${KUBEEDGE_VERSION}
kubectl taint nodes edge-node-02 edgenode=true:NoExecute
test sensor:
sudo apt-get install mosquitto-clients
sensor.sh
#!/bin/bash
BROKER="localhost"
TOPIC="sensors/home/livingroom"
while true; do
TEMP=$(awk -v min=20 -v max=30 'BEGIN{srand(); print min+rand()*(max-min)}')
HUM=$(awk -v min=40 -v max=80 'BEGIN{srand(); print min+rand()*(max-min)}')
PAYLOAD=$(printf '{"temperature": %.2f, "humidity": %.2f}' $TEMP $HUM)
echo "Sending: $PAYLOAD"
mosquitto_pub -h $BROKER -t $TOPIC -m "$PAYLOAD"
sleep 5
done
verifica :
mosquitto_sub -h localhost -t sensors/home/livingroom

189
add-on/NodeRed.yaml Normal file
View File

@@ -0,0 +1,189 @@
apiVersion: v1
kind: Namespace
metadata:
name: nodered
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: node-red-pvc
namespace: nodered
labels:
app: node-red
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-red
namespace: nodered
labels:
app: node-red
spec:
replicas: 1
selector:
matchLabels:
app: node-red
template:
metadata:
labels:
app: node-red
spec:
securityContext:
fsGroup: 1000
containers:
- name: nodered
image: nodered/node-red:4.1
args: ["--settings", "/config/settings.js"]
env:
- name: NODE_OPTIONS
value: "--trace-warnings"
ports:
- containerPort: 1880
securityContext:
runAsUser: 1000
runAsGroup: 1000
allowPrivilegeEscalation: false
resources:
limits:
memory: "512Mi"
cpu: "500m"
requests:
memory: "256Mi"
cpu: "250m"
livenessProbe:
httpGet:
path: /
port: 1880
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 1880
initialDelaySeconds: 5
periodSeconds: 5
volumeMounts:
- name: node-red-storage
mountPath: /data
- name: node-red-settings
mountPath: /config/settings.js
subPath: settings.js
volumes:
- name: node-red-storage
persistentVolumeClaim:
claimName: node-red-pvc
- name: node-red-settings
configMap:
name: node-red-settings
---
apiVersion: v1
kind: ConfigMap
metadata:
name: node-red-settings
namespace: nodered
data:
settings.js: |
module.exports = {
httpAdminRoot: '/',
httpNodeRoot: '/',
userDir: '/data',
flowFile: 'flows.json',
credentialSecret: 'yzM0ol6Zn5kd1234',
adminAuth: {
type: "credentials",
users: [{
username: "admin",
password: "",
permissions: "*"
}]
},
uiPort: process.env.PORT || 1880,
mqttReconnectTime: 15000,
serialReconnectTime: 15000,
debugMaxLength: 1000,
functionGlobalContext: {},
exportGlobalContextKeys: false,
logging: {
console: {
level: "info",
metrics: false,
audit: false
}
},
editorTheme: {
projects: {
enabled: false
}
}
};
---
apiVersion: v1
kind: Service
metadata:
name: node-red-service
namespace: nodered
labels:
app: node-red
spec:
type: ClusterIP
ports:
- port: 1880
targetPort: 1880
protocol: TCP
name: http
selector:
app: node-red
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: node-red-hpa
namespace: nodered
labels:
app: node-red
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: node-red
minReplicas: 1
maxReplicas: 3
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: node-red
namespace: nodered
spec:
hostnames:
- nodered.italiadatacenter.com
parentRefs:
- name: main-gateway
namespace: nginx-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: node-red-service
port: 1880

View File

@@ -0,0 +1,11 @@
kubectl get pods -n nodered
kubectl exec -it node-red-bd88bc7df-knqfw -n nodered -- node-red admin hash-pw
kubectl edit configmap node-red-settings -n nodered --->(set campo password password: "<bcrypt-hash-here>", nella sezione adminAuth)
kubectl delete pods node-red-bd88bc7df-knqfw -n nodered
user: admin
password:KAYQE1QA7uwUZ8uI

59
add-on/RabbitMQ.txt Normal file
View File

@@ -0,0 +1,59 @@
Install Operator
kubectl apply -f "https://github.com/rabbitmq/cluster-operator/releases/latest/download/cluster-operator.yml"
# namespace/rabbitmq-system created
# customresourcedefinition.apiextensions.k8s.io/rabbitmqclusters.rabbitmq.com created
# serviceaccount/rabbitmq-cluster-operator created
# role.rbac.authorization.k8s.io/rabbitmq-cluster-leader-election-role created
# clusterrole.rbac.authorization.k8s.io/rabbitmq-cluster-operator-role created
# rolebinding.rbac.authorization.k8s.io/rabbitmq-cluster-leader-election-rolebinding created
# clusterrolebinding.rbac.authorization.k8s.io/rabbitmq-cluster-operator-rolebinding created
# deployment.apps/rabbitmq-cluster-operator created
Define an instance
Mqinstance.yaml:
apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
name: production-ready
spec:
replicas: 1
resources:
requests:
cpu: 1
memory: 1Gi
limits:
cpu: 1
memory: 1Gi
rabbitmq:
additionalConfig: |
cluster_partition_handling = pause_minority
disk_free_limit.relative = 1.0
collect_statistics_interval = 10000
persistence:
storageClassName: csi-rbdfs-sc
storage: "5Gi"
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- production-ready
topologyKey: kubernetes.io/hostname
override:
statefulSet:
spec:
template:
spec:
containers: []
topologySpreadConstraints:
- maxSkew: 1
topologyKey: "topology.kubernetes.io/zone"
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/name: production-ready

View File

@@ -0,0 +1,44 @@
Download act_runner binary
mv act_runner-0.3.0-linux-amd64 act_runner
chmod +x ./act_runner
./act_runner --version
./act_runner register
Git server: https.//git.italiadatacener.com
token: SiP2B1Wth0FwORkLrIX7WYhho78IVaW3ZppO9vrx
label: runner1:host
start:
nohup ./act_runner daemon &
Install node
sudo apt update
sudo apt upgrade -y
sudo apt install -y curl ca-certificates gnupg
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs
verifica
node -v
npm -v
Installa docker:
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

21
add-on/backup.txt Normal file
View File

@@ -0,0 +1,21 @@
# Snapshot schedule
etcd-snapshot-schedule-cron: "0 */6 * * *"
etcd-snapshot-retention: 10
# Abilita S3 (MinIO)
etcd-s3: true
etcd-s3-endpoint: 127.0.0.1:3877
etcd-s3-access-key: minioadmin
etcd-s3-secret-key: KAYQE1QA7uwUZ8uI
etcd-s3-bucket: etcd-backups
etcd-s3-folder: idc-k8s
# Se MinIO senza TLS
etcd-s3-skip-ssl-verify: true
nohup kubectl port-forward svc/minio -n minio 9000 &
mc alias set local http://127.0.0.1:9000 minioadmin KAYQE1QA7uwUZ8uI
mc mb local/etcd-backups

344
add-on/cicd.txt Normal file
View File

@@ -0,0 +1,344 @@
data una struttura directory del progetto-A come da specifica che segue, creare i seguenti script in bash:
premessa: i file values.env contengono elenco coppie chiave/valore del tipo chiave1=valore1, ecc..
1) customize.sh: script che ha in input l'ambiente (dev,qa o prod) ed esegue la sostituzione nel file infrasructure.yaml della directory kubernetes dei tag del tipo <chiave1> con il relativo valore letto dal file values.env della directory corrispondente all'input fornito
1) build_container.sh : script che effettua la docker build di tutti i container presenti nella directory containers usando il nome della directory sotto containers come nome del container,nome della root directory come nome del repository e sha del commit come tag. lo script deve eseguire anche la push su un registry con precedente login con credenziali lette dal file properties.env
2) deploy.sh: script che effettua il deploy in kubernetes del file infrastructure.yaml contenuto nella directory kubernetes
struttura directory di progetto:
<dir> progetto-A
properties.env
build_src.sh
<dir> .gitea/
<dir> workflows
pipeline.yaml
<dir> containers
<dir> frontend
dockerfile
<dir> backend
dockerfile
<dir> env
<dir> dev
values.env
<dir> qa
values.env
<dir> prod
values.env
<dir> kubernetes
infrastructure.yaml
<dir> src
Provisioning:
env:
$organization= nome della società
$project=nome del progetto
1) Gitea: creazione Organization--> $organization(if not alreay exist)
2) Gitea: creazione progetto nome--> $project
3) Harbor: creazione project $project
4) X3 k8s creazione NAMSPACE,SA, ROLE, ROLEBINDING,KUBECONFIG per deploy su namespace (kube-provisioning.sh) per dev qa e prod
5) X3 Gitea: creazione secret KUBECONFIG_DEV, KUBECONFIG_QA e KUBECONFIG_PROD con kubeconfig generato da kube-provisioning.sh
6) harbor: creazione robot-user "git" con permessi full su repo del progetto ---> $registry_user, $registry_pass
7) harbor: creazione robot-user "k8spull" con permessi full su repo del progetto ---> $registry_user, $registry_pass
8) creazione secret e patch SA default
kubectl -n <$project> create secret docker-registry harbor-pull \
--docker-server=harbor.italiadatacenter.com \
--docker-username=robot\$<$project>+k8spull \
--docker-password=<robot usertoken> \
--docker-email=harbor@italiadatacenter.com
kubectl patch serviceaccount default -n athleteos-dev -p '{"imagePullSecrets":[{"name":"harbor-pull"}]}'
kubectl patch serviceaccount default -n <$project-qa> -p '{"imagePullSecrets":[{"name":"harbor-pull"}]}'
kubectl patch serviceaccount default -n <$project-prod> -p '{"imagePullSecrets":[{"name":"harbor-pull"}]}'
9) Gitea: creazione secret REGISTRY_USER -->$registry_user, REGISTRY_PASS -->$registry_pass
10)Gitea: poplazione repo con skeleton template
gitea-api-token
65fc5f07365bd3f89c5b9ddca3d2d2e7b3777a88
https://git.italiadatacenter.com/api/swagger
List Template
curl -X 'GET' \
'https://git.italiadatacenter.com/api/v1/repos/search?q=tmpl&topic=false&includeDesc=true&token=65fc5f07365bd3f89c5b9ddca3d2d2e7b3777a88' \
-H 'accept: application/json'
List repository:
curl -X 'GET' \
'https://git.italiadatacenter.com/api/v1/repos/search?token=65fc5f07365bd3f89c5b9ddca3d2d2e7b3777a88' \
-H 'accept: application/json'
Create repo from template:
curl -X 'POST' \
'https://git.italiadatacenter.com/api/v1/repos/STS_Lab/tmpl_nginx_node/generate?token=65fc5f07365bd3f89c5b9ddca3d2d2e7b3777a88' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"avatar": true,
"default_branch": "string",
"description": "string",
"git_content": true,
"git_hooks": true,
"labels": true,
"name": "secondo",
"owner": "STS_Lab",
"private": true,
"protected_branch": true,
"topics": true,
"webhooks": true
}'
creazione din una applicazione backstage che permetta la creazione di un repo da template con questa api:
curl -X 'POST' \
'https://git.italiadatacenter.com/api/v1/repos/STS_Lab/tmpl_nginx_node/generate?token=65fc5f07365bd3f89c5b9ddca3d2d2e7b3777a88' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"avatar": true,
"default_branch": "string",
"description": "string",
"git_content": true,
"git_hooks": true,
"labels": true,
"name": "secondo",
"owner": "STS_Lab",
"private": true,
"protected_branch": true,
"topics": true,
"webhooks": true
}'
la lista dei template disponbili è fornita dall'api:
curl -X 'GET' \
'https://git.italiadatacenter.com/api/v1/repos/search?q=tmpl&topic=false&includeDesc=true&token=65fc5f07365bd3f89c5b9ddca3d2d2e7b3777a88' \
-H 'accept: application/json'
l'utente deve poter creare un nuovo repo fornendo nome e template scelto dalla lista
---------------------------------
Harbor api:
https://harbor.italiadatacenter.com/devcenter-api-2.0
admin/KAYQE1QA7uwUZ8uI
Create project
curl -X 'POST' \
-u admin:KAYQE1QA7uwUZ8uI \
'https://harbor.italiadatacenter.com/api/v2.0/projects' \
-H 'accept: application/json' \
-H 'X-Resource-Name-In-Location: false' \
-H 'Content-Type: application/json' \
-d '{
"project_name": "secondo",
"public": false,
"metadata": {
"public": "false",
"enable_content_trust": "string",
"enable_content_trust_cosign": "string",
"prevent_vul": "string",
"severity": "string",
"auto_scan": "string",
"auto_sbom_generation": "string",
"reuse_sys_cve_allowlist": "string",
"proxy_speed_kb": "string",
"max_upstream_conn": "string"
},
"cve_allowlist": {
"id": 0,
"project_id": 0,
"expires_at": 0,
"items": [
{
"cve_id": "string"
}
],
"creation_time": "2026-03-21T17:12:18.108Z",
"update_time": "2026-03-21T17:12:18.108Z"
},
"storage_limit": 0
}'
creazionnr robot user
curl -X 'POST' \
-u admin:KAYQE1QA7uwUZ8uI \
'https://harbor.italiadatacenter.com/api/v2.0/robots' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"name": "secondobot",
"description": "scondo bot",
"secret": "string",
"level": "system",
"disable": true,
"duration": -1,
"permissions": [
{
"kind": "project",
"namespace": "secondo",
"access": [
{
"action": "delete",
"resource": "repository"
},
{
"action": "list",
"resource": "repository"
},
{
"action": "push",
"resource": "repository"
},
{
"action": "read",
"resource": "repository"
},
{
"action": "update",
"resource": "repository"
},
{
"action": "pull",
"resource": "repository"
}
]
}
]
}'
{
"creation_time": "2026-03-21T18:24:57.665Z",
"expires_at": -1,
"id": 44,
"name": "robot$secondobot",
"secret": "YxlIfu6o73zsQnKkgaWMdSc6MEwftVzk"
}
####### template modulari#########################################################
# 🧠 🎯 Cosè `git subtree` (in pratica)
👉 `subtree` ti permette di:
```text
includere un altro repository dentro una sottocartella
MANTENENDO la possibilità di aggiornarlo
```
👉 differenza chiave:
* il codice viene **copiato nel repo**
* ma mantiene un **legame logico con lorigine**
---
# 🔥 Perché è perfetto per template modulari
Scenario IDP:
```text
template-node
template-k8s
template-ci
```
👉 li vuoi combinare in:
```text
my-service/
app/
k8s/
ci/
```
👉 `subtree` fa ESATTAMENTE questo, in modo pulito
---
# 🏗️ Setup iniziale (step-by-step)
## 1⃣ Aggiungi il repo template
```bash
git remote add template-node https://gitea/template-node.git
git fetch template-node
```
---
## 2⃣ Importa il template
```bash
git subtree add \
--prefix=app \
template-node main \
--squash
```
---
### 🔍 Cosa succede
* copia contenuto in `app/`
* crea 1 commit (grazie a `--squash`)
* mantiene riferimento al repo remoto
---
# 🔄 Aggiornare il template
👉 quando il template evolve:
```bash
git subtree pull \
--prefix=app \
template-node main \
--squash
```
---
👉 risultato:
* aggiorna solo quella cartella
* merge automatico
---
# 🚀 Multi-template (use case IDP)
```bash
git subtree add --prefix=app template-node main --squash
git subtree add --prefix=k8s template-k8s main --squash
git subtree add --prefix=ci template-ci main --squash
```
---
👉 ottieni:
```text
repo finale:
app/
k8s/
ci/
```

17
add-on/clusterussuer.yaml Normal file
View File

@@ -0,0 +1,17 @@
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
email: alessandro.barucci66@gmail.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-production-key
solvers:
- http01:
gatewayHTTPRoute:
parentRefs:
- name: gateway
namespace: default
kind: Gateway

BIN
add-on/confmap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

118
add-on/create_ns.sh Normal file
View File

@@ -0,0 +1,118 @@
#!/usr/bin/env bash
###########################################################
#./kube-provisioning.sh dev cicd-user kubeconfig-dev.yaml
#arg1 = namespace
#arg2 = env (dev|qa|prod)
###########################################################
set -euo pipefail
############################################
# CONFIG
############################################
NAMESPACE=${1:-dev}-$2
SERVICE_ACCOUNT="deployer"
KUBECONFIG_FILE=${NAMESPACE}.yaml
echo "Namespace: $NAMESPACE"
echo "ServiceAccount: $SERVICE_ACCOUNT"
echo "Output kubeconfig: $KUBECONFIG_FILE"
############################################
# CHECK REQUIREMENTS
############################################
if ! command -v kubectl >/dev/null 2>&1; then
echo "kubectl not found"
exit 1
fi
############################################
# CREATE NAMESPACE
############################################
kubectl get ns "$NAMESPACE" >/dev/null 2>&1 || kubectl create namespace "$NAMESPACE"
############################################
# CREATE SERVICE ACCOUNT
############################################
kubectl -n "$NAMESPACE" get sa "$SERVICE_ACCOUNT" >/dev/null 2>&1 || \
kubectl -n "$NAMESPACE" create serviceaccount "$SERVICE_ACCOUNT"
############################################
# CREATE ROLE
############################################
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: namespace-deployer
namespace: $NAMESPACE
rules:
- apiGroups: ["", "apps", "batch", "networking.k8s.io"]
resources: ["*"]
verbs: ["*"]
EOF
############################################
# CREATE ROLE BINDING
############################################
kubectl -n "$NAMESPACE" get rolebinding namespace-deployer-binding >/dev/null 2>&1 || \
kubectl create rolebinding namespace-deployer-binding \
--role=namespace-deployer \
--serviceaccount=${NAMESPACE}:${SERVICE_ACCOUNT} \
-n "$NAMESPACE"
############################################
# GENERATE TOKEN
############################################
TOKEN=$(kubectl create token "$SERVICE_ACCOUNT" -n "$NAMESPACE")
############################################
# CLUSTER INFO
############################################
CLUSTER_NAME=$(kubectl config view --minify -o jsonpath='{.clusters[0].name}')
CLUSTER_SERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
CLUSTER_CA=$(kubectl config view --raw --minify -o jsonpath='{.clusters[0].cluster.certificate-authority-data}')
############################################
# GENERATE KUBECONFIG
############################################
cat <<EOF > "$KUBECONFIG_FILE"
apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority-data: ${CLUSTER_CA}
server: ${CLUSTER_SERVER}
name: ${CLUSTER_NAME}
contexts:
- context:
cluster: ${CLUSTER_NAME}
namespace: ${NAMESPACE}
user: ${SERVICE_ACCOUNT}
name: ${SERVICE_ACCOUNT}-${CLUSTER_NAME}
current-context: ${SERVICE_ACCOUNT}-${CLUSTER_NAME}
users:
- name: ${SERVICE_ACCOUNT}
user:
token: ${TOKEN}
EOF
echo
echo "Kubeconfig generated:"
echo "$KUBECONFIG_FILE"
echo
echo "Test command:"
echo "kubectl --kubeconfig=$KUBECONFIG_FILE get pods"

59
add-on/dbgate.yaml Normal file
View File

@@ -0,0 +1,59 @@
apiVersion: v1
kind: Namespace
metadata:
name: dbgate
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dbgate
namespace: dbgate
spec:
replicas: 1
selector:
matchLabels:
app: dbgate
template:
metadata:
labels:
app: dbgate
spec:
containers:
- name: dbgate
image: dbgate/dbgate:latest
ports:
- containerPort: 3000
env:
- name: CONNECTIONS
value: ""
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
---
apiVersion: v1
kind: Service
metadata:
name: dbgate
namespace: dbgate
spec:
selector:
app: dbgate
ports:
- port: 80
targetPort: 3000
type: ClusterIP

113
add-on/devops.txt Normal file
View File

@@ -0,0 +1,113 @@
kubectl create namespace devops
dbdevops.yaml:
---
apiVersion: v1
kind: Secret
metadata:
name: pg-app-user
namespace: demo-apps
type: kubernetes.io/basic-auth
stringData:
username: devops
password: KAYQE1QA7uwUZ8uI
---
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: pg-devops
namespace: devops
spec:
instances: 3
storage:
size: 1Gi
storageClass: csi-rbdfs-sc
walStorage:
storageClass: csi-rbdfs-sc
size: 1Gi
bootstrap:
initdb:
database: devops
owner: admin
secret:
name: pg-app-user
postgresql:
parameters:
max_connections: "300"
shared_buffers: "1GB"
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "2"
memory: "2Gi"
--- pgadmin -------------------
apiVersion: apps/v1
kind: Deployment
metadata:
name: pgadmin-deployment
spec:
replicas: 1
selector:
matchLabels:
app: pgadmin
template:
metadata:
labels:
app: pgadmin
spec:
containers:
- name: pgadmin
image: dpage/pgadmin4
ports:
- containerPort: 80
env:
- name: PGADMIN_DEFAULT_EMAIL
value: pgadmin@italiadatacenter.com
- name: PGADMIN_DEFAULT_PASSWORD
value: KAYQE1QA7uwUZ8uI
- name: PGADMIN_CONFIG_ENHANCED_COOKIE_PROTECTION
value: "false"
---
apiVersion: v1
kind: Service
metadata:
name: pgadmin-service
spec:
selector:
app: pgadmin
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: demo-route
namespace: demo-apps
spec:
hostnames:
- poc3.italiadatacenter.com
parentRefs:
- name: main-gateway
namespace: nginx-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: pgadmin-service
port: 80

30
add-on/edgenodeport.yaml Normal file
View File

@@ -0,0 +1,30 @@
apiVersion: v1
kind: Service
metadata:
annotations:
meta.helm.sh/release-name: cloudcore
meta.helm.sh/release-namespace: kubeedge
labels:
k8s-app: kubeedge
kubeedge: cloudcore
name: kubeedge-nodeport
namespace: kubeedge
spec:
ports:
- appProtocol: tcp
name: cloudhub
nodePort: 30868
port: 10000
protocol: TCP
targetPort: 10000
- appProtocol: tcp2
name: cloudhub2
nodePort: 30869
port: 10002
protocol: TCP
targetPort: 10002
selector:
k8s-app: kubeedge
kubeedge: cloudcore
sessionAffinity: None
type: NodePort

347
add-on/get_helm.sh Normal file
View File

@@ -0,0 +1,347 @@
#!/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
local latest_release_url="https://get.helm.sh/helm3-latest-version"
local latest_release_response=""
if [ "${HAS_CURL}" == "true" ]; then
latest_release_response=$( curl -L --silent --show-error --fail "$latest_release_url" 2>&1 || true )
elif [ "${HAS_WGET}" == "true" ]; then
latest_release_response=$( wget "$latest_release_url" -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 v3.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 v3.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

88
add-on/gitea-action.txt Normal file
View File

@@ -0,0 +1,88 @@
apiVersion: v1
kind: Secret
metadata:
name: gitea-runner-secret
type: Opaque
stringData:
token: G3uEVBJ1TrlFhlwiWfE7seymUPnN1OgyeQHy7T7e
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: act-runner-vol
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: csi-rbdfs-sc
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: act-runner
name: act-runner
spec:
replicas: 1
selector:
matchLabels:
app: act-runner
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: act-runner
spec:
hostAliases:
- ip: "140.82.121.3"
hostnames:
- "github.com"
restartPolicy: Always
volumes:
- name: docker-certs
emptyDir: {}
- name: runner-data
persistentVolumeClaim:
claimName: act-runner-vol
- name: dockersock
hostPath:
path: /var/run/docker.sock
containers:
- name: runner
image: gitea/act_runner:nightly-dind-rootless
command: ["sh", "-c", "while ! nc -z localhost 2376 </dev/null; do echo 'waiting for docker daemon...'; sleep 5; done; /sbin/tini -- run.sh"]
env:
- name: DOCKER_HOST
value: tcp://localhost:2376
- name: DOCKER_CERT_PATH
value: /certs/client
- name: DOCKER_TLS_VERIFY
value: "1"
- name: GITEA_INSTANCE_URL
value: https://git.italiadatacenter.com/
- name: GITEA_RUNNER_REGISTRATION_TOKEN
valueFrom:
secretKeyRef:
name: gitea-runner-secret
key: token
volumeMounts:
- name: docker-certs
mountPath: /certs
- name: runner-data
mountPath: /data
- name: daemon
image: docker:23.0.6-dind
env:
- name: DOCKER_TLS_CERTDIR
value: /certs
securityContext:
privileged: true
volumeMounts:
- name: docker-certs
mountPath: /certs

161
add-on/gitea-action2.txt Normal file
View File

@@ -0,0 +1,161 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: gitea-act-runner-config
namespace: gitea
data:
config.yaml: |
log:
level: debug
cache:
enabled: false
container:
valid_volumes:
- /certs
options: |
--add-host=docker:host-gateway -v /certs:/certs
-e "DOCKER_HOST=tcp://docker:2376/"
-e "DOCKER_TLS_VERIFY=1"
-e "DOCKER_CERT_PATH=/certs/client"
---
apiVersion: v1
kind: ConfigMap
metadata:
name: gitea-docker-daemon-config
namespace: gitea
data:
daemon.json: |
{ "insecure-registries": ["git.italiadatacenter.com"] }
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: gitea-act-runner-dind
namespace: gitea
spec:
replicas: 1
selector:
matchLabels:
app: gitea-act-runner-dind
serviceName: gitea-act-runner-dind
template:
metadata:
labels:
app: gitea-act-runner-dind
spec:
initContainers:
- name: gitea-act-runner-init
image: gitea/gitea:1.22.1-rootless
# Creates temporary gitea instance, generates token and saves it to act-runner
command:
- bash
- -exc
- |
sed '/[server]/a LOCAL_ROOT_URL = https://git.italiadatacenter.com/' /data/gitea/conf/app.ini > /tmp/app.ini; test -e /act-runner-data/.runner || gitea actions generate-runner-token > /act-runner-data/token
env:
- name: GITEA_APP_INI
value: /tmp/app.ini
- name: GITEA_CUSTOM
value: /data/gitea
- name: GITEA_WORK_DIR
value: /data
volumeMounts:
- name: gitea-shared-storage
mountPath: /data
readOnly: true
- name: gitea-act-runner-data
mountPath: /act-runner-data
containers:
- name: runner
image: gitea/act_runner:nightly
# Container only for gitea, so we can choose the dind variant (rootless or not)
image: gitea/act_runner:0.2.10
env:
- name: DOCKER_HOST
value: tcp://127.0.0.1:2376
- name: DOCKER_CERT_PATH
value: /certs/client
- name: DOCKER_TLS_VERIFY
value: "1"
- name: GITEA_RUNNER_REGISTRATION_TOKEN_FILE
value: /data/token
- name: CONFIG_FILE
value: /config.yaml
- name: GITEA_INSTANCE_URL
value: https://git.italiadatacenter.com
- name: CONFIG_FILE
value: /actrunner/config.yaml
volumeMounts:
- name: gitea-act-runner-data
mountPath: /data
- name: docker-certs
mountPath: /certs/client
- name: runner-config
mountPath: /actrunner
## Avoid subPath because it cannot be updated
## https://github.com/kubernetes/kubernetes/issues/50345
#mountPath: /actrunner/config.yaml
#subPath: config.yaml
- name: daemon
## Rootless works for simple cases, but not for docker buildx
#image = "docker:27.1.2-dind-rootless"
image = "docker:27.1.2-dind"
env:
- name: DOCKER_TLS_CERTDIR
value: /certs
- name: DOCKER_HOST
value: tcp://127.0.0.1:2376
- name: DOCKER_TLS_VERIFY
value: 1
securityContext:
privileged: true
volumeMounts:
- name: docker-certs
mountPath: /certs/client
- name: gitea-docker-daemon-config
## This one for rootless variant
#mountPath: /home/rootless/.config/docker
## This other for regular variant
mountPath: /etc/docker
## Avoid subPath because it cannot be updated
## https://github.com/kubernetes/kubernetes/issues/50345
#mountPath: /home/rootless/.config/docker/daemon.json
#mountPath: /etc/docker/daemon.json
#subPath: daemon.json
volumes:
- name: docker-certs
emptyDir: {}
- name: gitea-act-runner-config
configMap:
name: gitea-act-runner-config
- name: gitea-act-runner-data
persistentVolumeClaim:
claimName: gitea-act-runner
- name: gitea-shared-storage
persistentVolumeClaim:
claimName: gitea-shared-storage
readOnly: true
- name: gitea-docker-daemon-config
configMap:
name: gitea-docker-daemon-config
volumeClaimTemplates:
- metadata:
name: gitea-act-runner-data
namespace: gitea
spec:
accessModes:
- ReadWriteOnce
storageClassName: standard
resources:
requests:
storage: 1Gi

87
add-on/gitea-workflow.txt Normal file
View File

@@ -0,0 +1,87 @@
name: Build and Push Docker Image
on:
push:
branches:
- main
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Harbor
uses: docker/login-action@v3
with:
registry: harbor.italiadatacenter.com
username: ${{ secrets.HARBOR_USERNAME }}
password: ${{ secrets.HARBOR_PASSWORD }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: harbor.italiadatacenter.com/test/nginxtest:${{ github.sha }}
#run: /root/work/pipeline/build_container.sh ${{ github.event.repository.name }}
---------------------------------------------------------------------
name: Build and Push Docker Images from Containers
on:
push:
branches: [ main ]
workflow_dispatch: # Permette esecuzione manuale
jobs:
# Job per elencare le directory con Dockerfile e creare una matrice
list-containers:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set matrix for containers
id: set-matrix
run: |
# Trova tutte le directory contenenti Dockerfile in containers/
dirs=$(find containers -name Dockerfile -exec dirname {} \; | sort)
# Converte in JSON per la matrice (es. [{"dir": "containers/app1"}, {"dir": "containers/app2"}])
matrix=$(echo "$dirs" | jq -R -s -c 'split("\n")[:-1] | map({dir: .})')
echo "matrix=$matrix" >> $GITHUB_OUTPUT
- name: Log in to Docker registry
uses: docker/login-action@v3
with:
registry: ghcr.io # Esempio: GitHub Container Registry; cambia se usi Docker Hub
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Job per buildare e pushare ogni immagine usando la matrice
build:
needs: list-containers
runs-on: ubuntu-latest
strategy:
matrix:
container: ${{ fromJson(needs.list-containers.outputs.matrix) }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ${{ matrix.container.dir }} # Contesto del build (la directory del Dockerfile)
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

100
add-on/gitea.sh Normal file
View File

@@ -0,0 +1,100 @@
kubectl cnpg psql pg-devops -n devops
CREATE DATABASE giteadb;
CREATE USER gitea WITH PASSWORD 'KAYQE1QA7uwUZ8uI';
GRANT ALL PRIVILEGES ON DATABASE giteadb TO gitea;
ALTER DATABASE giteadb OWNER TO gitea;
helm repo add gitea https://dl.gitea.io/charts/
helm repo update
kubectl create namespace gitea
cat <<EOF |cat >values.yaml -
replicaCount: 1
image:
repository: gitea/gitea
tag: 1.22.0
pullPolicy: IfNotPresent
strategy:
type: Recreate
service:
http:
type: ClusterIP
port: 3000
ssh:
type: ClusterIP
port: 22
redis-cluster:
enabled: false
redis:
enabled: false
ingress:
enabled: false
persistence:
enabled: true
storageClass: csi-rbdfs-sc
size: 10Gi
postgresql:
enabled: false
postgresql-ha:
enabled: false
gitea:
admin:
username: gitadmin
password: KAYQE1QA7uwUZ8uI
email: gitadmin@italiadatacenter.com
config:
database:
DB_TYPE: postgres
HOST: pg-devops-rw.devops.svc:5432
NAME: giteadb
USER: gitea
PASSWD: KAYQE1QA7uwUZ8uI
SSL_MODE: disable
server:
ROOT_URL: https://git.italiadatacenter.com/
SSH_DOMAIN: git.italiadatacenter.com
SSH_PORT: 22
security:
INSTALL_LOCK: true
EOF
helm upgrade --install gitea gitea-charts/gitea --namespace gitea -f values.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: gitea
namespace: gitea
spec:
hostnames:
- git.italiadatacenter.com
parentRefs:
- name: main-gateway
namespace: nginx-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: gitea-http
port: 3000

123
add-on/grafana.txt Normal file
View File

@@ -0,0 +1,123 @@
Aggiungere repository Helm Grafana
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
----
kubectl create namespace grafana
----
grafana-values.yaml:
replicas: 1
adminUser: admin
adminPassword: KAYQE1QA7uwUZ8uI5
service:
type: ClusterIP
port: 80
persistence:
enabled: true
size: 10Gi
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
---
helm install grafana grafana/grafana -n grafana -f grafana-values.yaml
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: grafana
spec:
hostnames:
- tekton.italiadatacenter.com
parentRefs:
- name: main-gateway
namespace: nginx-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: grafana
port: 80
****************** TEST ****************************
Accesso alla UI Grafana
Aprire browser:
http://localhost:3000
Login:
user: admin
password: KAYQE1QA7uwUZ8uI5
link svc:
grafana.grafana.svc.cluster.local
---------------------------------------
Aggiungere InfluxDB come datasource
In Grafana:
Connections
Data Sources
Add data source
InfluxDB
Configurazione:
URL
http://influxdb:8086
Organization:
demo-org
Token:
my-super-token
Bucket:
demo-bucket
Salva.
6⃣ Test datasource
Click:
Save & Test
Se corretto:
Datasource is working
7⃣ Creare dashboard
In Grafana:
Create
Dashboard
Add panel
Query esempio (InfluxDB Flux):
from(bucket: "demo-bucket")
|> range(start: -1h)

201
add-on/harbor.sh Normal file
View File

@@ -0,0 +1,201 @@
#HARBOR
kubectl create namespace harbor
helm repo add harbor https://helm.goharbor.io
helm repo update
cat <<EOF | cat > harbor-cert.yaml -
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: harbor-tls
namespace: harbor
spec:
secretName: harbor-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- harbor.italiadatacenter.com
EOF
kubectl apply -f harbor-cert.yaml
cat <<EOF | cat > harborvalues.yaml -
# -----------------------
# EXPOSURE
# -----------------------
expose:
# Set how to expose the service. Set the type as "ingress", "clusterIP", "nodePort" or "loadBalancer"
# and fill the information in the corresponding section
type: clusterIP
externalURL: https://harbor.italiadatacenter.com
# -----------------------
# ADMIN
# -----------------------
harborAdminPassword: "KAYQE1QA7uwUZ8uI"
# -----------------------
# PERSISTENCE
# -----------------------
persistence:
enabled: true
persistentVolumeClaim:
registry:
storageClass: csi-rbdfs-sc
size: 50Gi
jobservice:
storageClass: csi-rbdfs-sc
size: 2Gi
trivy:
storageClass: csi-rbdfs-sc
size: 2Gi
# -----------------------
# POSTGRESQL (EXTERNAL)
# -----------------------
database:
type: external
external:
host: pg-devops-rw.devops.svc
port: 5432
username: harbor
password: "KAYQE1QA7uwUZ8uI"
database: registry
sslmode: require
# -----------------------
# REDIS (EXTERNAL)
# -----------------------
redis:
type: external
external:
addr: redis.redis.svc.cluster.local:6379
password: "KAYQE1QA7uwUZ8uI"
database: 0
# -----------------------
# DISABLE INTERNAL SERVICES
# -----------------------
postgresql:
enabled: false
redisInternal:
enabled: false
# -----------------------
# COMPONENTS
# -----------------------
trivy:
enabled: true
metrics:
enabled: false
EOF
kubectl cnpg psql pg-devops -n devops
CREATE DATABASE registry;
CREATE USER harbor WITH PASSWORD 'KAYQE1QA7uwUZ8uI';
GRANT ALL PRIVILEGES ON DATABASE registry TO harbor;
ALTER DATABASE registry OWNER TO harbor;
#test
kubectl run psql-test --rm -it --image=postgres:16 -- psql -h pg-prod-rw.database.svc -U harbor
kubectl run redis-test --rm -it --image=redis:7 -- redis-cli -h redis.redis.svc.cluster.local -a Japp0cam
helm install harbor harbor/harbor -n harbor -f harborvalues.yaml
--- httproute & body setting nginx ----
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: harbor
namespace: harbor
spec:
hostnames:
- harbor.italiadatacenter.com
parentRefs:
- name: main-gateway
namespace: nginx-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: harbor
port: 80
---
apiVersion: gateway.nginx.org/v1alpha1
kind: ClientSettingsPolicy
metadata:
name: gateway-client-settings
spec:
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: main-gateway
body:
maxSize: "0"
EOF
#test
#Login UI:
https://harbor.pigreco66.it/ (admin(Japp0cam)
#push
docker login harbor.italiadatacenter.com
docker pull nginx:1.25
docker tag nginx:1.25 harbor.italiadatacenter.com/library/nginx:1.25
docker push harbor.italiadatacenter.com/library/nginx:1.25
#pull
docker rmi harbor.pigreco66.it/library/nginx:1.25
docker pull harbor.pigreco66.it/library/nginx:1.25
#pull da k8s
#STEP 1 Creare Robot Account in Harbor
#Harbor UI → Projects → (es. library o apps) → Robot Accounts
#Nome: k8s-pull
#Permessi:
#✔️ Repository → Pull
kubectl create secret docker-registry harbor-pull \
-n default \
--docker-server=harbor.italiadatacenter.com \
--docker-username=robot$k8s-pull \
--docker-password=ir0ELEJEFg804qljh2p32ALzIsMJepWt \
--docker-email=harbor@italiadatacenter.com
#per namespace nuovi
kubectl patch serviceaccount default -n default -p '{"imagePullSecrets":[{"name":"harbor-pull"}]}'
#applicare per i vecchi:
kubectl patch serviceaccount default -n primo-dev -p '{"imagePullSecrets":[{"name":"harbor-pull"}]}'
#test
kubectl run test-nginx --image=harbor.italiadatacenter.com/library/nginx:1.25 --restart=Never -n poc
kubectl -n primo-dev create secret docker-registry harbor-pull \
--docker-server=harbor.italiadatacenter.com \
--docker-username=robot\$primo+primo \
--docker-password=agQLiKJ8K5qmBWhO1bHngzb9UorPLIw1 \
--docker-email=harbor@italiadatacenter.com
kubectl patch serviceaccount default -n primo-dev -p '{"imagePullSecrets":[{"name":"harbor-pull"}]}'

BIN
add-on/influxdb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

76
add-on/influxdb.txt Normal file
View File

@@ -0,0 +1,76 @@
helm repo add influxdata https://helm.influxdata.com/
helm repo update
----
kubectl create namespace influxdb
----
influxdb-values.yaml:
image:
repository: influxdb
tag: 2.7
persistence:
enabled: true
size: 20Gi
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 1
memory: 1Gi
service:
type: ClusterIP
port: 8086
adminUser:
organization: sts-lab
bucket: demo-bucket
user: admin
password: KAYQE1QA7uwUZ8uI5
token: my-super-token
----
helm install influxdb influxdata/influxdb2 --namespace influxdb -f influxdb-values.yaml
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: influxdb
spec:
hostnames:
- poc2.italiadatacenter.com
parentRefs:
- name: main-gateway
namespace: nginx-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: influxdb-influxdb2
port: 8086
****************** TEST ****************************
echo $(kubectl get secret influxdb-influxdb2-auth -o "jsonpath={.data['admin-password']}" --namespace influxdb | base64 --decode)
logon UI
http://localhost:8086
user: admin
password: KAYQE1QA7uwUZ8uI5
TEST API:
curl http://localhost:8086/health
link svc:
influxdb-influxdb2.influxdb.svc.cluster.local

164
add-on/install_edgenode.sh Normal file
View File

@@ -0,0 +1,164 @@
#!/usr/bin/env bash
set -euo pipefail
# Configurazione (override con variabili d'ambiente prima di eseguire lo script)
KUBEEDGE_VERSION="${KUBEEDGE_VERSION:-v1.22.0}"
CLOUD_MASTER_IP="${CLOUD_MASTER_IP:-89.105.78.161}"
EDGE_NODE_NAME="${EDGE_NODE_NAME:-edge-node-02}"
KUBEEDGE_TOKEN="${KUBEEDGE_TOKEN:-26477f03e3d0209870acdf724478f1d875e1328f8ea3408d74f3d7d109ad02be.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NzQ5OTI1NzB9.YxfikSixBrX7bvQxgxXYpbwLJHg0SAQ9mQ7kblBWQrk}"
CONTAINERD_VERSION="1.6.14"
RUNC_VERSION="1.1.3"
CNI_VERSION="1.1.1"
echo "==== EDGE NODE INSTALL START ===="
echo "KUBEEDGE_VERSION=${KUBEEDGE_VERSION}"
echo "CLOUD_MASTER_IP=${CLOUD_MASTER_IP}"
echo "EDGE_NODE_NAME=${EDGE_NODE_NAME}"
echo "KUBEEDGE_TOKEN=${KUBEEDGE_TOKEN}"
if ! command -v sudo >/dev/null 2>&1; then
echo "Errore: sudo non trovato"
exit 1
fi
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "${TMP_DIR}"' EXIT
echo "[1/8] Download e installazione containerd ${CONTAINERD_VERSION}"
cd "${TMP_DIR}"
wget -q "https://github.com/containerd/containerd/releases/download/v${CONTAINERD_VERSION}/containerd-${CONTAINERD_VERSION}-linux-amd64.tar.gz"
sudo tar Cxzvf /usr/local "containerd-${CONTAINERD_VERSION}-linux-amd64.tar.gz"
echo "[2/8] Download e installazione runc ${RUNC_VERSION}"
wget -q "https://github.com/opencontainers/runc/releases/download/v${RUNC_VERSION}/runc.amd64"
sudo install -m 755 runc.amd64 /usr/local/sbin/runc
echo "[3/8] Download e installazione CNI plugins ${CNI_VERSION}"
wget -q "https://github.com/containernetworking/plugins/releases/download/v${CNI_VERSION}/cni-plugins-linux-amd64-v${CNI_VERSION}.tgz"
sudo mkdir -p /opt/cni/bin
sudo tar Cxzvf /opt/cni/bin "cni-plugins-linux-amd64-v${CNI_VERSION}.tgz"
echo "[4/8] Configurazione containerd"
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml >/dev/null
sudo sed -i '/SystemdCgroup = true/d' /etc/containerd/config.toml
sudo curl -fsSL https://raw.githubusercontent.com/containerd/containerd/main/containerd.service -o /etc/systemd/system/containerd.service
echo "[5/8] Configurazione rete CNI"
sudo mkdir -p /etc/cni/net.d
cat <<'EOF' | sudo tee /etc/cni/net.d/10-containerd-net.conflist >/dev/null
{
"cniVersion": "1.0.0",
"name": "containerd-net",
"plugins": [
{
"type": "bridge",
"bridge": "cni0",
"isGateway": true,
"ipMasq": true,
"promiscMode": true,
"ipam": {
"type": "host-local",
"ranges": [
[{
"subnet": "10.88.0.0/16"
}],
[{
"subnet": "2001:db8:4860::/64"
}]
],
"routes": [
{ "dst": "0.0.0.0/0" },
{ "dst": "::/0" }
]
}
},
{
"type": "portmap",
"capabilities": {"portMappings": true}
}
]
}
EOF
echo "[6/8] Avvio e abilitazione containerd"
sudo systemctl daemon-reload
sudo systemctl enable --now containerd
echo "[7/8] Installazione keadm ${KUBEEDGE_VERSION}"
cd "${TMP_DIR}"
curl -fsSL "https://github.com/kubeedge/kubeedge/releases/download/${KUBEEDGE_VERSION}/keadm-${KUBEEDGE_VERSION}-linux-amd64.tar.gz" | tar -xz
sudo mv "keadm-${KUBEEDGE_VERSION}-linux-amd64/keadm/keadm" /usr/local/bin/
echo "[8/8] Join edge node al cloud master"
sudo keadm join \
--cloudcore-ipport="${CLOUD_MASTER_IP}:10000" \
--edgenode-name="${EDGE_NODE_NAME}" \
--token="${KUBEEDGE_TOKEN}" \
--kubeedge-version="${KUBEEDGE_VERSION}"
echo "Creazione script di cleanup edge"
cat <<'EOF' | sudo tee /usr/local/bin/edge-cleanup.sh >/dev/null
#!/usr/bin/env bash
set -euo pipefail
echo "==== EDGE NODE CLEANUP START ===="
echo "Timestamp: $(date)"
echo "[1] Checking orphan processes..."
ORPHANS=$(ps -eo pid,ppid,cmd | awk '$2 == 1 {print $1}')
for PID in ${ORPHANS}; do
if [ "${PID}" != "1" ]; then
echo "Killing orphan PID: ${PID}"
kill -9 "${PID}" 2>/dev/null || true
fi
done
echo "[2] Cleaning containerd..."
if command -v crictl >/dev/null 2>&1; then
crictl ps -a --state Exited -q | xargs -r crictl rm || true
crictl pods --state NotReady -q | xargs -r crictl rmp || true
crictl rmi --prune || true
else
echo "crictl not found, skipping..."
fi
echo "[3] Restarting containerd..."
systemctl restart containerd || true
echo "[4] Cleaning kubelet state (soft)..."
find /var/lib/kubelet/pods -mindepth 1 -maxdepth 1 -type d -mtime +1 -exec rm -rf {} + || true
echo "[5] Restarting kubelet + edgecore..."
systemctl restart kubelet || true
systemctl restart edgecore || true
echo "[6] Checking MQTT port..."
ss -tulnp | grep 1883 || echo "WARNING: Mosquitto not listening"
echo "==== EDGE NODE CLEANUP DONE ===="
EOF
sudo chmod +x /usr/local/bin/edge-cleanup.sh
echo "Creazione service systemd edge-cleanup"
cat <<'EOF' | sudo tee /etc/systemd/system/edge-cleanup.service >/dev/null
[Unit]
Description=Edge Node Cleanup
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/edge-cleanup.sh
RemainAfterExit=true
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable edge-cleanup
echo "==== EDGE NODE INSTALL DONE ===="

View File

@@ -0,0 +1,11 @@
kubectl create namespace cert-manager
helm repo add jetstack https://charts.jetstack.io
helm repo update
# Install versione consigliata
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--set installCRDs=true \
--wait
# Verifica
kubectl -n cert-manager get pods

View File

@@ -0,0 +1,7 @@
helm repo add rancher-stable https://releases.rancher.com/server-charts/stable
kubectl create namespace cattle-system
helm install rancher rancher-stable/rancher \
--namespace cattle-system \
--set hostname=k8s.italiadatacenter.com \
--set bootstrapPassword=admin

7
add-on/installa_helm.sh Normal file
View File

@@ -0,0 +1,7 @@
# scarica helm (esempio Linux AMD64)
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh
# verifica
helm version

BIN
add-on/k8s-secret.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

23
add-on/longhornui.yaml Normal file
View File

@@ -0,0 +1,23 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: longhornui
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/cluster-issuer: "letsencrypt-production"
spec:
tls:
- hosts:
- longhorn.pigreco66.it
secretName: longhornui-tls
rules:
- host: longhorn.pigreco66.it
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: longhorn-frontend
port:
number: 80

111
add-on/minio.txt Normal file
View File

@@ -0,0 +1,111 @@
##helm
helm repo add minio https://charts.min.io/
helm repo update
##values.yaml:
mode: distributed
replicas: 2
drivesPerNode: 1
persistence:
enabled: true
storageClass: csi-rbdfs-sc # 👈 IL TUO STORAGE CLASS
size: 50Gi
resources:
requests:
memory: 1Gi
cpu: 500m
limits:
memory: 2Gi
cpu: 1
rootUser: minioadmin
rootPassword: KAYQE1QA7uwUZ8uI
service:
type: ClusterIP
ingress:
enabled: false
consoleService:
type: ClusterIP
##Deploy
helm install minio minio/minio -n minio --create-namespace -f minio_values.yaml
Accesso:
kubectl port-forward svc/minio -n minio 9000
kubectl port-forward svc/minio-console -n storage 9001
##per pod us nodi diversi
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- minio
topologyKey: "kubernetes.io/hostname"
#################INFO##########################
NAME: minio
LAST DEPLOYED: Sun Mar 29 16:23:17 2026
NAMESPACE: minio
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
MinIO can be accessed via port 9000 on the following DNS name from within your cluster:
minio.minio.cluster.local
To access MinIO from localhost, run the below commands:
1. export POD_NAME=$(kubectl get pods --namespace minio -l "release=minio" -o jsonpath="{.items[0].metadata.name}")
2. kubectl port-forward $POD_NAME 9000 --namespace minio
Read more about port forwarding here: http://kubernetes.io/docs/user-guide/kubectl/kubectl_port-forward/
You can now access MinIO server on http://localhost:9000. Follow the below steps to connect to MinIO server with mc client:
1. Download the MinIO mc client - https://min.io/docs/minio/linux/reference/minio-mc.html#quickstart
2. export MC_HOST_minio-local=http://$(kubectl get secret --namespace minio minio -o jsonpath="{.data.rootUser}" | base64 --decode):$(kubectl get secret --namespace minio minio -o jsonpath="{.data.rootPassword}" | base64 --decode)@localhost:9000
###svc nodeport per accessi backup etc
apiVersion: v1
kind: Service
metadata:
annotations:
meta.helm.sh/release-name: minio
meta.helm.sh/release-namespace: minio
labels:
app: minio
release: minio
name: minio-nodeport
namespace: minio
spec:
ports:
- name: http
nodePort: 30877
port: 9000
protocol: TCP
targetPort: 9000
selector:
app: minio
release: minio
sessionAffinity: None
type: NodePort

104
add-on/mosquitto.yaml Normal file
View File

@@ -0,0 +1,104 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: mosquitto-config
namespace: mqtt
data:
mosquitto.conf: |
listener 1883
allow_anonymous true
persistence true
persistence_location /mosquitto/data/
log_dest stdout
log_type all
# opzionale: retained messages
persistence_file mosquitto.db
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mosquitto-pvc
namespace: mqtt
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: csi-rbdfs-sc # 👈 cambia se necessario
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mosquitto
namespace: mqtt
spec:
replicas: 1
selector:
matchLabels:
app: mosquitto
template:
metadata:
labels:
app: mosquitto
spec:
containers:
- name: mosquitto
image: eclipse-mosquitto:2
ports:
- containerPort: 1883
volumeMounts:
- name: config
mountPath: /mosquitto/config/mosquitto.conf
subPath: mosquitto.conf
- name: data
mountPath: /mosquitto/data
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
volumes:
- name: config
configMap:
name: mosquitto-config
- name: data
persistentVolumeClaim:
claimName: mosquitto-pvc
---
apiVersion: v1
kind: Service
metadata:
name: mqtt-broker
namespace: mqtt
spec:
selector:
app: mosquitto
ports:
- name: mqtt
port: 1883
targetPort: 1883
type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
name: mqtt-broker-nodeport
namespace: mqtt
spec:
ports:
- appProtocol: tcp
name: mqtt
nodePort: 31883
port: 1883
protocol: TCP
targetPort: 1883
selector:
app: mosquitto
sessionAffinity: None
type: NodePort

BIN
add-on/mqtt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

38
add-on/mysql.txt Normal file
View File

@@ -0,0 +1,38 @@
helm repo add mysql-operator https://mysql.github.io/mysql-operator/
helm repo update
helm install my-mysql-operator mysql-operator/mysql-operator --namespace mysql-operator --create-namespace
--db instance
kubectl create secret generic mypwds \
--from-literal=rootUser=root \
--from-literal=rootHost=% \
--from-literal=rootPassword="sakila"
apiVersion: mysql.oracle.com/v2
kind: InnoDBCluster
metadata:
name: mycluster
spec:
secretName: mypwds
tlsUseSelfSigned: true
instances: 3
router:
instances: 1
--- test
$> kubectl run --rm -it myshell --image=container-registry.oracle.com/mysql/community-operator -- mysqlsh root@mycluster --sql
If you don't see a command prompt, try pressing enter.
******
MySQL mycluster SQL> SELECT @@hostname
+-------------+
| @@hostname |
+-------------+
| mycluster-0 |
+-------------+
This section utilizes the {innodbclustername}.{namespace}.svc.cluster.local form when connecting; and typically refers to the {innodbclustername} shorthand form that assumes the default namespace. See Section 3.4, “MySQL InnoDB Cluster Service Explanation” for additional information.

View File

@@ -0,0 +1,30 @@
apiVersion: v1
kind: Service
metadata:
annotations:
meta.helm.sh/release-name: rke2-ingress-nginx
meta.helm.sh/release-namespace: kube-system
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: rke2-ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: rke2-ingress-nginx
app.kubernetes.io/part-of: rke2-ingress-nginx
app.kubernetes.io/version: 1.13.4
helm.sh/chart: rke2-ingress-nginx-4.13.400
name: ingress-nginx-nodeport
namespace: kube-system
spec:
ports:
- appProtocol: https
name: https
nodePort: 30864
port: 443
protocol: TCP
targetPort: https
selector:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: rke2-ingress-nginx
app.kubernetes.io/name: rke2-ingress-nginx
sessionAffinity: None
type: NodePort

38
add-on/package-lock.json generated Normal file
View File

@@ -0,0 +1,38 @@
{
"name": "add-on",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"chokidar": "^5.0.0"
}
},
"node_modules/chokidar": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
"integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
"dependencies": {
"readdirp": "^5.0.0"
},
"engines": {
"node": ">= 20.19.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/readdirp": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
"integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
"engines": {
"node": ">= 20.19.0"
},
"funding": {
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
}
}
}

5
add-on/package.json Normal file
View File

@@ -0,0 +1,5 @@
{
"dependencies": {
"chokidar": "^5.0.0"
}
}

62
add-on/pgdb.txt Normal file
View File

@@ -0,0 +1,62 @@
kubectl create namespace <dbxx>
dbxx.yaml.yaml:
---
apiVersion: v1
kind: Secret
metadata:
name: pg-app-user
namespace: <dbxx>
type: kubernetes.io/basic-auth
stringData:
username: devops
password: KAYQE1QA7uwUZ8uI
---
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: pg-devops
namespace: <dbxx>
spec:
instances: 3
storage:
size: 1Gi
storageClass: csi-rbdfs-sc
walStorage:
storageClass: csi-rbdfs-sc
size: 1Gi
bootstrap:
initdb:
database: devops
owner: admin
secret:
name: pg-app-user
postgresql:
parameters:
max_connections: "300"
shared_buffers: "1GB"
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "2"
memory: "2Gi"
kubectl cnpg psql pg-devops -n devops
CREATE DATABASE giteadb;
CREATE USER gitea WITH PASSWORD 'KAYQE1QA7uwUZ8uI';
GRANT ALL PRIVILEGES ON DATABASE giteadb TO gitea;
ALTER DATABASE giteadb OWNER TO gitea;

71
add-on/pipeline.txt Normal file
View File

@@ -0,0 +1,71 @@
#!/bin/bash
# Usage: ./customize.sh dev|qa|prod
ENV=$1
VALUES_FILE="env/$ENV/values.env"
YAML_FILE="kubernetes/infrastructure.yaml"
if [ ! -f "$VALUES_FILE" ]; then
echo "File $VALUES_FILE non trovato."
exit 1
fi
if [ ! -f "$YAML_FILE" ]; then
echo "File $YAML_FILE non trovato."
exit 1
fi
while IFS='=' read -r key value; do
sed -i "s|<$key>|$value|g" "$YAML_FILE"
done < "$VALUES_FILE"
echo "Sostituzione completata per ambiente $ENV."
#!/bin/bash
# Carica variabili dal file properties.env
source properties.env
# Controlla che le variabili siano impostate
if [ -z "$REGISTRY_URL" ] || [ -z "$REGISTRY_USER" ] || [ -z "$REGISTRY_PASS" ]; then
echo "REGISTRY_URL, REGISTRY_USER o REGISTRY_PASS non impostate in properties.env"
exit 1
fi
REPO_NAME=$(basename "$PWD")
COMMIT_SHA=$(git rev-parse --short HEAD)
# Login al registry
echo "$REGISTRY_PASS" | docker login "$REGISTRY_URL" -u "$REGISTRY_USER" --password-stdin
for dir in containers/*/; do
CONTAINER_NAME=$(basename "$dir")
DOCKERFILE="$dir/dockerfile"
IMAGE_TAG="${REGISTRY_URL}/${REPO_NAME}/${CONTAINER_NAME}:${COMMIT_SHA}"
if [ -f "$DOCKERFILE" ]; then
docker build -t "$IMAGE_TAG" -f "$DOCKERFILE" "$dir"
docker push "$IMAGE_TAG"
echo "Build e push completate: $IMAGE_TAG"
else
echo "Dockerfile non trovato in $dir"
fi
done
#!/bin/bash
# Effettua il deploy del file infrastructure.yaml in Kubernetes
YAML_FILE="kubernetes/infrastructure.yaml"
if [ ! -f "$YAML_FILE" ]; then
echo "File $YAML_FILE non trovato."
exit 1
fi
kubectl apply -f "$YAML_FILE"
echo "Deploy completato."

View File

@@ -0,0 +1,169 @@
# creazione secret, SA, Role e Rolebinding all'interno del namespace applicativo
kubectl create secret docker-registry harbor-regcred \
-n poc \
--docker-server=harbor.pigreco66.it \
--docker-username=robot$tekton \
--docker-password=p2oZtqcUJafMAlX0eUzgHax9fv0ML8te \
--docker-email=alessandro.barucci66@gmail.com
kubectl create secret generic harbor-push-secret -n poc --from-file=config.json=config.json
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: tekton-deployer
namespace: poc
imagePullSecrets:
- name: harbor-regcred
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: tekton-deployer
namespace: poc
rules:
- apiGroups: ["", "apps", "batch", "networking.k8s.io"]
resources: ["*"]
verbs: ["*"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: tekton-deployer
namespace: poc
subjects:
- kind: ServiceAccount
name: tekton-deployer
namespace: poc
roleRef:
kind: Role
name: tekton-deployer
apiGroup: rbac.authorization.k8s.io
EOF
#Pipeline che refernzia task remoti --> apply -f su namespace centralizzato tekton-pipelines
#kubectl apply -f pipedep.yaml -n tekton-pipelines
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: deploy-infrastructure
spec:
description: |
This pipeline clones a git repo, builds a Docker image with Kaniko and
pushes it to a registry
params:
- name: repo-url
type: string
- name: image-reference
type: string
- name: dockerfile
type: string
- name: namespace
type: string
workspaces:
- name: shared-data
- name: docker-credentials
tasks:
- name: fetch-source
taskRef:
resolver: cluster
params:
- name: name
value: git-clone
- name: namespace
value: tekton-pipelines
- name: kind
value: task
workspaces:
- name: output
workspace: shared-data
params:
- name: url
value: $(params.repo-url)
- name: build-push
runAfter: ["fetch-source"]
taskRef:
resolver: cluster
params:
- name: name
value: kaniko
- name: namespace
value: tekton-pipelines
- name: kind
value: task
workspaces:
- name: source
workspace: shared-data
- name: dockerconfig
workspace: docker-credentials
params:
- name: IMAGE
value: $(params.image-reference)
- name: DOCKERFILE
value: $(params.dockerfile)
- name: deploy
runAfter: [build-push]
taskRef:
resolver: cluster
params:
- name: name
value: kubectl-apply
- name: namespace
value: tekton-pipelines
- name: kind
value: task
params:
- name: namespace
value: $(params.namespace)
workspaces:
- name: source
workspace: shared-data
#PipelineRun creato su namespace applicativo che refenzia pipeline remote
#kubectl create -f pipedeprun2.yaml -n poc
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: clone-build-push-run-
spec:
serviceAccountName: tekton-deployer
pipelineRef:
resolver: cluster
params:
- name: namespace
value: tekton-pipelines
- name: name
value: deploy-infrastructure
- name: kind
value: pipeline
podTemplate:
securityContext:
fsGroup: 65532
workspaces:
- name: shared-data
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 1Gi
- name: docker-credentials
secret:
secretName: harbor-push-secret
params:
- name: repo-url
value: https://gitea.pigreco66.it/pigreco/poc.git
- name: image-reference
value: harbor.pigreco66.it/library/nginx:1.30
- name: dockerfile
value: ./container/nginx/dockerfile
- name: namespace
value: poc

349
add-on/pipelines.sh Normal file
View File

@@ -0,0 +1,349 @@
#installo task community "git-clone"
#kubectl apply -f https://api.hub.tekton.dev/v1/resource/tekton/task/git-clone/0.10/raw -n
kubectl apply -f https://github.com/tektoncd/catalog/raw/main/task/git-clone/0.10/git-clone.yaml -n tekton-pipelines
cat <<EOF | kubectl -n tekton-pipelines apply -f -
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: clone-read
spec:
description: |
This pipeline clones a git repo, then echoes the README file to the stout.
params:
- name: repo-url
type: string
description: The git repo URL to clone from.
- name: image
type: string
description: The name (reference) of the image to build.
- name: dockerfile
type: string
description: The path to the Dockerfile to execute (default: ./Dockerfile)
workspaces:
- name: shared-data
description: |
This workspace contains the cloned repo files, so they can be read by the
next task.
tasks:
- name: fetch-source
taskRef:
name: git-clone
workspaces:
- name: output
workspace: shared-data
params:
- name: url
value: $(params.repo-url)
- name: show-readme
runAfter: ["fetch-source"]
taskRef:
name: show-readme
workspaces:
- name: source
workspace: shared-data
- name: docker-build
runAfter: ["show-readme"]
taskRef:
name: docker-build
workspaces:
- name: output
workspace: shared-data
params:
- name: image
value: $(params.image)
- name: dockerfile
value: $(params.dockerfile)
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: show-readme
spec:
description: Read and display README file.
workspaces:
- name: source
steps:
- name: read
image: alpine:latest
script: |
#!/usr/bin/env sh
cat $(workspaces.source.path)/README.md
EOF
cat <<EOF | kubectl -n tekton-pipelines create -f -
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: clone-read-run-
spec:
pipelineRef:
name: clone-read
podTemplate:
securityContext:
fsGroup: 65532
workspaces:
- name: shared-data
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 1Gi
params:
- name: repo-url
value: https://gitea.pigreco66.it/pigreco/poc.git
- name: image
value: nginx
- name: dockerfile
value: ./container/nginx/dockerfile
EOF
#BUILD Container
#installo task community "kaniko"
#kubectl apply -f https://api.hub.tekton.dev/v1/resource/tekton/task/kaniko/0.7/raw
kubectl apply -f https://github.com/tektoncd/catalog/raw/main/task/kaniko/0.7/kaniko.yaml -n -n tekton-pipelines
cat <<EOF | kubectl -n tekton-pipelines apply -f -
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: clone-build-push
spec:
description: |
This pipeline clones a git repo, builds a Docker image with Kaniko and
pushes it to a registry
params:
- name: repo-url
type: string
- name: image-reference
type: string
- name: dockerfile
type: string
workspaces:
- name: shared-data
- name: docker-credentials
tasks:
- name: fetch-source
taskRef:
name: git-clone
workspaces:
- name: output
workspace: shared-data
params:
- name: url
value: $(params.repo-url)
- name: build-push
runAfter: ["fetch-source"]
taskRef:
name: kaniko
workspaces:
- name: source
workspace: shared-data
- name: dockerconfig
workspace: docker-credentials
params:
- name: IMAGE
value: $(params.image-reference)
- name: DOCKERFILE
value: $(params.dockerfile)
EOF
cat <<EOF | kubectl -n tekton-pipelines create -f -
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: clone-build-push-run-
spec:
pipelineRef:
name: clone-build-push
podTemplate:
securityContext:
fsGroup: 65532
workspaces:
- name: shared-data
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 1Gi
- name: docker-credentials
secret:
secretName: harbor-push-secret
params:
- name: repo-url
value: https://gitea.pigreco66.it/pigreco/poc.git
- name: image-reference
value: harbor.pigreco66.it/library/nginx:1.30
- name: dockerfile
value: ./container/nginx/dockerfile
EOF
# Build, push, deploy
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: tekton-deployer
namespace: tekton-pipelines
imagePullSecrets:
- name: harbor-regcred
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: tekton-deployer
namespace: poc
rules:
- apiGroups: ["", "apps", "batch", "networking.k8s.io"]
resources: ["*"]
verbs: ["*"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: tekton-deployer
namespace: poc
subjects:
- kind: ServiceAccount
name: tekton-deployer
namespace: tekton-pipelines
roleRef:
kind: Role
name: tekton-deployer
apiGroup: rbac.authorization.k8s.io
EOF
cat <<EOF | kubectl -n tekton-pipelines apply -f -
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: kubectl-apply
namespace: tekton-pipelines
spec:
workspaces:
- name: source
params:
- name: namespace
type: string
- name: manifest
type: string
default: infrastructure.yaml
steps:
- name: apply
image: bitnami/kubectl:latest
script: |
set -e
echo "Deploying $(params.manifest) to namespace $(params.namespace)"
kubectl apply \
-f $(workspaces.source.path)/$(params.manifest) \
-n $(params.namespace)
EOF
cat <<EOF | kubectl -n tekton-pipelines apply -f -
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: clone-build-push
spec:
description: |
This pipeline clones a git repo, builds a Docker image with Kaniko and
pushes it to a registry
params:
- name: repo-url
type: string
- name: image-reference
type: string
- name: dockerfile
type: string
- name: namespace
type: string
workspaces:
- name: shared-data
- name: docker-credentials
tasks:
- name: fetch-source
taskRef:
name: git-clone
workspaces:
- name: output
workspace: shared-data
params:
- name: url
value: $(params.repo-url)
- name: build-push
runAfter: ["fetch-source"]
taskRef:
name: kaniko
workspaces:
- name: source
workspace: shared-data
- name: dockerconfig
workspace: docker-credentials
params:
- name: IMAGE
value: $(params.image-reference)
- name: DOCKERFILE
value: $(params.dockerfile)
- name: deploy
runAfter: [build-push]
taskRef:
name: kubectl-apply
params:
- name: namespace
value: $(params.namespace)
workspaces:
- name: source
workspace: shared-data
EOF
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: clone-build-push-run-
spec:
serviceAccountName: tekton-deployer
pipelineRef:
name: deploy-infrastructure
podTemplate:
securityContext:
fsGroup: 65532
workspaces:
- name: shared-data
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 1Gi
- name: docker-credentials
secret:
secretName: harbor-push-secret
params:
- name: repo-url
value: https://gitea.pigreco66.it/pigreco/poc.git
- name: image-reference
value: harbor.pigreco66.it/library/nginx:1.30
- name: dockerfile
value: ./container/nginx/dockerfile
- name: namespace
value: poc

View File

@@ -0,0 +1,31 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: longhorn-volv-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 2Gi
---
apiVersion: v1
kind: Pod
metadata:
name: volume-test
namespace: default
spec:
containers:
- name: volume-test
image: nginx:stable-alpine
imagePullPolicy: IfNotPresent
volumeMounts:
- name: volv
mountPath: /data
ports:
- containerPort: 80
volumes:
- name: volv
persistentVolumeClaim:
claimName: longhorn-volv-pvc

66
add-on/poc-testweb.yaml Normal file
View File

@@ -0,0 +1,66 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 250m
memory: 256Mi
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
labels:
app: nginx
spec:
type: ClusterIP
selector:
app: nginx
ports:
- port: 80 # Porta esposta dal Service
targetPort: 80 # Porta del container NGINX
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/cluster-issuer: "letsencrypt-production"
spec:
tls:
- hosts:
- poc.pigreco66.it
secretName: myapp-tls
rules:
- host: poc.pigreco66.it
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80

315
add-on/postgresql.sh Normal file
View File

@@ -0,0 +1,315 @@
kubectl apply --server-side -f https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.28/releases/cnpg-1.28.0.yaml--force-conflicts
curl -sSfL https://github.com/cloudnative-pg/cloudnative-pg/raw/main/hack/install-cnpg-plugin.sh | sudo sh -s -- -b /usr/local/bin
kubectl create namespace database
database.yaml:
---
apiVersion: v1
kind: Secret
metadata:
name: pg-app-user
namespace: demo-apps
type: kubernetes.io/basic-auth
stringData:
username: admin
password: admin
---
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: pg-test
namespace: demo-apps
spec:
instances: 3
storage:
size: 1Gi
storageClass: csi-rbdfs-sc
walStorage:
storageClass: csi-rbdfs-sc
size: 1Gi
bootstrap:
initdb:
database: testdb
owner: admin
secret:
name: pg-app-user
postgresql:
parameters:
max_connections: "300"
shared_buffers: "1GB"
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "2"
memory: "2Gi"
#test
kubectl run psql-client -n database --rm -it --image=postgres:16 --env="PGPASSWORD=admin" -- psql -h pg-test-rw.demo-apps.svc -U admin -d appdb
kubectl patch pvc pg-test-1-wal -n demo_apps -p '{"spec":{"resources":{"requests":{"storage":"32Gi"}}}}'
backup:
barmanObjectStore:
destinationPath: s3://pg-backups/prod
endpointURL: http://minio.minio.svc:9000
s3Credentials:
accessKeyId:
name: s3-creds
key: ACCESS_KEY
secretAccessKey:
name: s3-creds
key: SECRET_KEY
--- pgadmin -------------------
apiVersion: apps/v1
kind: Deployment
metadata:
name: pgadmin-deployment
spec:
replicas: 1
selector:
matchLabels:
app: pgadmin
template:
metadata:
labels:
app: pgadmin
spec:
containers:
- name: pgadmin
image: dpage/pgadmin4
ports:
- containerPort: 80
env:
- name: PGADMIN_DEFAULT_EMAIL
value: pgadmin@italiadatacenter.com
- name: PGADMIN_DEFAULT_PASSWORD
value: KAYQE1QA7uwUZ8uI
---
apiVersion: v1
kind: Service
metadata:
name: pgadmin-service
spec:
selector:
app: pgadmin
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: demo-route
namespace: demo-apps
spec:
hostnames:
- poc3.italiadatacenter.com
parentRefs:
- name: main-gateway
namespace: nginx-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: pgadmin-service
port: 80
--------------------------------------------------------------------------------
cat <<EOF | kubectl -n database apply -f -
# This StorageClass is optimized for use with CloudNativePG.
# It disables storage-level replication and ensures data is local to the pod.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn-cnpg-strict-local
provisioner: driver.longhorn.io
# allowVolumeExpansion is crucial for scaling database storage without downtime.
allowVolumeExpansion: true
# reclaimPolicy: Delete ensures that when a PVC is deleted, the underlying
# Longhorn volume is also removed, preventing orphaned storage.
reclaimPolicy: Delete
parameters:
# This is the most important setting. We rely on CloudNativePG for replication,
# so we only need one copy at the storage layer to avoid write amplification.
numberOfReplicas: "1"
# dataLocality: strict-local guarantees that the volume data will be stored
# on the same node as the pod that uses it. This is essential for performance
# and for aligning with a true shared-nothing architecture.
dataLocality: "strict-local"
# A longer timeout for stale replicas is suitable for database workloads.
staleReplicaTimeout: "2880" # 48 hours in minutes
# Default filesystem.
fsType: "ext4"
EOF
kubectl cnpg psql pg-devops -n devops
CREATE DATABASE giteadb;
CREATE USER gitea WITH PASSWORD 'KAYQE1QA7uwUZ8uI';
GRANT ALL PRIVILEGES ON DATABASE giteadb TO gitea;
ALTER DATABASE giteadb OWNER TO gitea;
cluster production ready:
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: mycluster
namespace: database
spec:
instances: 3 # → 3 nodi per HA reale
primaryUpdateStrategy: unsupervised
failover: # → Failover automatico
promoteTimeout: 5m
targetPromotionRule: "prefer-high-promotion-score"
# ---------------------------
# STORAGE (PRODUCTION)
# ---------------------------
storage:
size: 200Gi
storageClass: fast-rbd # Ceph, SSD, GP3 ecc.
resizeInUse: true
walStorage: # Consigliato in produzione
size: 50Gi
storageClass: fast-rbd
# ---------------------------
# WAL ARCHIVING (S3/MINIO)
# ---------------------------
walArchive:
enabled: true
destinationPath: "s3://mybucket/wal/"
s3Credentials:
accessKeyId:
name: cnpg-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: cnpg-s3-creds
key: SECRET_ACCESS_KEY
endpointURL: "https://s3.myregion.amazonaws.com"
region: "myregion"
encryption: AES256
# ---------------------------
# BACKUP AUTOMATICI
# ---------------------------
backup:
barmanObjectStore:
destinationPath: "s3://mybucket/basebackup/"
endpointURL: "https://s3.myregion.amazonaws.com"
s3Credentials:
accessKeyId:
name: cnpg-s3-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: cnpg-s3-creds
key: SECRET_ACCESS_KEY
wal:
compression: bzip2
encryption: AES256
retentionPolicy: "30d" # → 30 giorni di retention
monitoring:
enablePodMonitor: true
# ---------------------------
# TLS INTERNO (RACCOMANDATO)
# ---------------------------
certificates:
serverTLSSecret: cnpg-server-tls
clientTLSSecret: cnpg-client-tls
# ---------------------------
# RESOURCE MANAGEMENT
# ---------------------------
resources:
requests:
cpu: "1"
memory: "2Gi"
limits:
cpu: "4"
memory: "8Gi"
# ---------------------------
# ANTI-AFFINITY & PDB
# ---------------------------
affinity:
enablePodAntiAffinity: true
topologyKey: "kubernetes.io/hostname"
podDisruptionBudget:
minAvailable: 2
# ---------------------------
# STARTUP & HEALTH
# ---------------------------
postgresql:
shared_preload_libraries:
- "pg_stat_statements"
- "auto_explain"
parameters:
max_connections: "300"
shared_buffers: "2GB"
effective_cache_size: "6GB"
maintenance_work_mem: "512MB"
wal_compression: "on"
wal_level: "replica"
max_wal_size: "4GB"
checkpoint_timeout: "15min"
synchronous_commit: "remote_apply"
# ---------------------------
# SYNCHRONOUS REPLICATION
# ---------------------------
replication:
synchronous:
mode: " quorum "
number: 1 # One sync replica; others async
# ---------------------------
# SERVICE & NETWORKING
# ---------------------------
service:
type: ClusterIP
primary:
type: ClusterIP
replicas:
type: ClusterIP
# ---------------------------
# ENCRYPTION AT REST (OPZIONALE)
# ---------------------------
encryption:
enabled: true
mode: aes256-gcm

BIN
add-on/python.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@@ -0,0 +1,19 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: rancher
namespace: cattle-system
spec:
hostnames:
- k8s.italiadatacenter.com
parentRefs:
- name: main-gateway
namespace: nginx-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: rancher
port: 80

BIN
add-on/redis.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

82
add-on/redis.sh Normal file
View File

@@ -0,0 +1,82 @@
kubectl create namespace redis
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
cat <<EOF | cat > redisvalues.yaml -
architecture: replication
auth:
enabled: true
password: KAYQE1QA7uwUZ8uI
master:
persistence:
enabled: true
storageClass: csi-rbdfs-sc
size: 5Gi
resources:
requests:
cpu: 100m
memory: 256Mi
replica:
replicaCount: 2
persistence:
enabled: true
storageClass: csi-rbdfs-sc
size: 5Gi
resources:
requests:
cpu: 100m
memory: 256Mi
sentinel:
enabled: true
replicas: 3
resources:
requests:
cpu: 50m
memory: 64Mi
metrics:
enabled: false
EOF
helm install redis bitnami/redis -n redis -f redisvalues.yaml
#test
kubectl run redis-client -n redis --rm -it --image=redis:7.2 -- redis-cli -h redis.redis.svc.cluster.local -a KAYQE1QA7uwUZ8uI
###########################################################################################################################
Redis(R) can be accessed via port 6379 on the following DNS name from within your cluster:
redis.redis.svc.cluster.local for read only operations
For read/write operations, first access the Redis(R) Sentinel cluster, which is available in port 26379 using the same domain name above.
To get your password run:
export REDIS_PASSWORD=$(kubectl get secret --namespace redis redis -o jsonpath="{.data.redis-password}" | base64 -d)
To connect to your Redis(R) server:
1. Run a Redis(R) pod that you can use as a client:
kubectl run --namespace redis redis-client --restart='Never' --env REDIS_PASSWORD=$REDIS_PASSWORD --image registry-1.docker.io/bitnami/redis:latest --command -- sleep infinity
Use the following command to attach to the pod:
kubectl exec --tty -i redis-client \
--namespace redis -- bash
2. Connect using the Redis(R) CLI:
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h redis -p 6379 # Read only operations
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h redis -p 26379 # Sentinel access
To connect to your database from outside the cluster execute the following commands:
kubectl port-forward --namespace redis svc/redis 6379:6379 &
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h 127.0.0.1 -p 6379

View File

@@ -0,0 +1 @@
powershell -ExecutionPolicy Bypass -File .\add-on\validate-scss.ps1 -RootPath "C:\Users\Public\git\limec-frontend\src\"

87
add-on/sonaquebe.txt Normal file
View File

@@ -0,0 +1,87 @@
########### repo helm ################
helm repo add sonarqube https://SonarSource.github.io/helm-chart-sonarqube
helm repo update
########### creazione ns e secret db ################
kubectl create namespace sonarqube
kubectl create secret generic sonarqube-database-cred \
--from-literal=username=sonarqube \
--from-literal=password=KAYQE1QA7uwUZ8uI \
-n sonarqube
########### creazione database ################
kubectl cnpg psql pg-devops -n devops
CREATE DATABASE sonarqube;
CREATE USER sonarqube WITH PASSWORD 'KAYQE1QA7uwUZ8uI';
GRANT ALL PRIVILEGES ON DATABASE sonarqube TO sonarqube;
ALTER DATABASE sonarqube OWNER TO sonarqube;
########### Values.yaml per installazione helm ################
service:
type: ClusterIP
postgresql:
enabled: false
jdbcOverwrite:
enabled: true
jdbcUrl: "jdbc:postgresql://pg-devops-rw.devops.svc.cluster.local:5432/sonarqube"
jdbcUsername: "postgres"
jdbcSecretName: "sonarqube-database-cred"
jdbcSecretPasswordKey: "password"
readinessProbe:
initialDelaySeconds: 300 # Increase initial delay to accommodate the database start time
timeoutSeconds: 60
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
livenessProbe:
initialDelaySeconds: 360 # Ensure the application has enough time to start
timeoutSeconds: 60
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
startupProbe:
initialDelaySeconds: 300 # Allow for sufficient startup time
timeoutSeconds: 60
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
########### installazione helm ################
helm upgrade -f sonarvalues.yaml --install -n sonarqube sonarqube sonarqube/sonarqube --set community.enabled=true,monitoringPasscode="KAYQE1QA7uwUZ8uI"
########### httproute ################
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: sonarqube
namespace: sonarqube
spec:
hostnames:
- sonarqube.italiadatacenter.com
parentRefs:
- name: main-gateway
namespace: nginx-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: sonarqube-sonarqube
port: 9000
admin
$KAYQE1QA7uwUZ8uI

197
add-on/tekton.sh Normal file
View File

@@ -0,0 +1,197 @@
kubectl create namespace tekton-pipelines
kubectl apply -f https://infra.tekton.dev/tekton-releases/pipeline/previous/v1.7.0/release.yaml
kubectl edit cm feature-flags -n tekton-pipelines
data:
enable-api-fields: "stable"
disable-affinity-assistant: "false"
enable-tekton-oci-bundles: "true"
enable-custom-tasks: "true"
kubectl edit cm config-defaults -n tekton-pipelines
data:
default-timeout-minutes: "60"
default-service-account: "tekton-sa"
cat <<EOF | cat > tekton-sa.yaml -
apiVersion: v1
kind: ServiceAccount
metadata:
name: tekton-sa
namespace: tekton-pipelines
EOF
kubectl apply -f tekton-sa.yaml
#STEP 1 Creare Robot Account in Harbor
#Harbor UI → Projects → (es. library o apps) → Robot Accounts
#Nome: k8s-pull
#Permessi:
#✔️ FULL permission
kubectl create secret docker-registry harbor-regcred \
-n tekton-pipelines \
--docker-server=harbor.italiadatacenter.com \
--docker-username=robot$tekton \
--docker-password=pyyMRe2kRIp6LQmIh8jaSWquL1mDtz04 \
--docker-email=harbor@italiadatacenter.com
cat <<EOF > config.json
{
"auths": {
"harbor.italiadatacenter.com": {
"username": "robot\$tekton",
"password": "pyyMRe2kRIp6LQmIh8jaSWquL1mDtz04",
"email": "harbor@italiadatacenter.com",
"auth": "$(echo -n 'robot$tekton:pyyMRe2kRIp6LQmIh8jaSWquL1mDtz04' | base64)"
}
}
}
EOF
kubectl create secret generic harbor-push-secret -n tekton-pipelines --from-file=config.json=config.json
kubectl patch sa tekton-sa \
-n tekton-pipelines \
-p '{"imagePullSecrets":[{"name":"harbor-regcred"}]}'
cat <<EOF | cat > tekton-workspace.yaml -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: tekton-workspace
namespace: tekton-pipelines
spec:
accessModes:
- ReadWriteOnce
storageClassName: csi-rbdfs-sc
resources:
requests:
storage: 10Gi
EOF
kubectl apply -f tekton-workspace.yaml -n tekton-pipelines
#Tekton Triggers
kubectl apply -f https://storage.googleapis.com/tekton-releases/triggers/latest/release.yaml -n tekton-pipelines
#Tekton Dashboard
kubectl apply -f https://storage.googleapis.com/tekton-releases/dashboard/latest/release.yaml -n tekton-pipelines
cat <<EOF | cat > tekton-ingress.yaml -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tekton-dashboard
namespace: tekton-pipelines
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/cluster-issuer: "letsencrypt-production"
spec:
tls:
- hosts:
- tekton.pigreco66.it
secretName: myapp-tls
rules:
- host: tekton.pigreco66.it
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tekton-dashboard
port:
number: 9097
EOF
cat <<EOF | cat > tekton-httproute.yaml -
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: tekton
namespace: tekton-pipelines
spec:
hostnames:
- tekton.italiadatacenter.com
parentRefs:
- name: main-gateway
namespace: nginx-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: tekton-dashboard
port: 9097
EOF
kubectl apply -f tekton-httproute.yaml -n tekton-pipelines
kubectl label namespace tekton-pipelines \
pod-security.kubernetes.io/enforce=privileged \
pod-security.kubernetes.io/audit=privileged \
pod-security.kubernetes.io/warn=privileged \
--overwrite
#installazione cli
curl -LO https://github.com/tektoncd/cli/releases/download/v0.43.0/tkn_0.43.0_Linux_x86_64.tar.gz
tar xvf tkn_0.43.0_Linux_x86_64.tar.gz
sudo mv tkn /usr/local/bin/
#TEST
cat <<EOF | cat > tekton-test.yaml -
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: hello
namespace: tekton-pipelines
spec:
steps:
- name: echo
image: alpine
script: |
echo "Tekton OK"
---
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: hello-pipeline
namespace: tekton-pipelines
spec:
tasks:
- name: hello
taskRef:
name: hello
---
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
name: hello-pipeline-run
spec:
pipelineRef:
name: hello-pipeline
params:
- name: username
value: "Tekton"
EOF
kubectl apply -f tekton-test.yaml -n tekton-pipelines

134
add-on/validate-scss.ps1 Normal file
View File

@@ -0,0 +1,134 @@
param (
[Parameter(Mandatory = $true)]
[string]$RootPath,
[string]$NpxSassPackage = "sass@1.77.8",
[bool]$NoErrorCss = $true
)
$ErrorActionPreference = 'Stop'
try {
$resolvedRoot = (Resolve-Path -Path $RootPath).Path
} catch {
Write-Host "ERROR: Root path not found: $RootPath" -ForegroundColor Red
exit 2
}
Write-Host "Scanning SCSS files in: $resolvedRoot" -ForegroundColor Cyan
function Get-SassRunner {
param(
[Parameter(Mandatory = $true)]
[string]$StartPath,
[Parameter(Mandatory = $true)]
[string]$PinnedNpxPackage
)
$current = $StartPath
while ($true) {
$localSass = Join-Path $current "node_modules\\.bin\\sass.cmd"
if (Test-Path $localSass) {
return @{
Command = $localSass
PrefixArgs = @()
Source = "local"
}
}
$parent = Split-Path -Path $current -Parent
if (-not $parent -or $parent -eq $current) {
break
}
$current = $parent
}
$npxCmd = Get-Command npx.cmd -ErrorAction SilentlyContinue
if ($npxCmd) {
cmd /d /c "npx -y -p $PinnedNpxPackage sass --version >nul 2>&1" | Out-Null
if ($LASTEXITCODE -eq 0) {
return @{
Command = $npxCmd.Source
PrefixArgs = @("-y", "-p", $PinnedNpxPackage, "sass")
Source = "npx:$PinnedNpxPackage"
}
}
}
$sassCmd = Get-Command sass.cmd -ErrorAction SilentlyContinue
if ($sassCmd) {
cmd /d /c "sass --version >nul 2>&1" | Out-Null
if ($LASTEXITCODE -eq 0) {
return @{
Command = $sassCmd.Source
PrefixArgs = @()
Source = "global"
}
}
}
return $null
}
$sassRunner = Get-SassRunner -StartPath $resolvedRoot -PinnedNpxPackage $NpxSassPackage
if (-not $sassRunner) {
Write-Host "ERROR: No working Sass runner found (local sass.cmd, global sass, or npx sass)." -ForegroundColor Red
exit 3
}
Write-Host "Using Sass runner: $($sassRunner.Source) [$($sassRunner.Command)]" -ForegroundColor DarkCyan
# Find all SCSS files recursively from the given root path.
$files = Get-ChildItem -Path $resolvedRoot -Recurse -File -Filter "*.scss"
if ($files.Count -eq 0) {
Write-Host "No SCSS files found." -ForegroundColor Yellow
exit 0
}
$hasErrors = $false
$checkedCount = 0
$errorCount = 0
foreach ($file in $files) {
$checkedCount += 1
Write-Host "Checking: $($file.FullName)" -ForegroundColor Gray
# Syntax-only validation: compile to NUL to avoid creating/opening any CSS files.
$sassArgs = @($sassRunner.PrefixArgs) + @('--no-source-map', '--style=compressed', '--quiet', "--load-path=$resolvedRoot")
if ($NoErrorCss) {
$sassArgs += '--no-error-css'
}
$sassArgs += @($file.FullName, 'NUL')
$previousErrorAction = $ErrorActionPreference
$ErrorActionPreference = 'Continue'
try {
$result = & $sassRunner.Command @sassArgs 2>&1 | Out-String
$exitCode = $LASTEXITCODE
} finally {
$ErrorActionPreference = $previousErrorAction
}
if ($exitCode -ne 0) {
$hasErrors = $true
$errorCount += 1
Write-Host ""
Write-Host "ERROR in $($file.FullName)" -ForegroundColor Red
Write-Host $result -ForegroundColor Yellow
Write-Host "----------------------------------------"
}
}
Write-Host ""
Write-Host "Checked files: $checkedCount"
if (-not $hasErrors) {
Write-Host "All SCSS files are syntactically valid." -ForegroundColor Green
exit 0
}
Write-Host "SCSS files with errors: $errorCount" -ForegroundColor Red
exit 1

BIN
add-on/vol.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB