diff --git a/k8s/apps/pasarguard/configmap-scripts.yaml b/k8s/apps/pasarguard/configmap-scripts.yaml new file mode 100644 index 0000000..860349c --- /dev/null +++ b/k8s/apps/pasarguard/configmap-scripts.yaml @@ -0,0 +1,233 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: pasarguard-scripts + labels: + app: pasarguard-node +data: + init-uuid.sh: | + #!/bin/bash + set -e + echo "Started" + # NODE_NAME is already set via environment variable + NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace) + + # Get DNS name from node label xray-node-address + DNS_NAME=$(kubectl get node "${NODE_NAME}" -o jsonpath='{.metadata.labels.xray-node-address}') + + if [ -z "${DNS_NAME}" ]; then + echo "ERROR: Node ${NODE_NAME} does not have label 'xray-node-address'" + exit 1 + fi + + echo "Node: ${NODE_NAME}" + echo "DNS Name from label: ${DNS_NAME}" + + # Use DNS name for ConfigMap name to ensure uniqueness + CONFIGMAP_NAME="node-uuid-${DNS_NAME//./-}" + + echo "Checking ConfigMap: ${CONFIGMAP_NAME}" + + # Check if ConfigMap exists and get UUID + if kubectl get configmap "${CONFIGMAP_NAME}" -n "${NAMESPACE}" &>/dev/null; then + echo "ConfigMap exists, reading UUID..." + API_KEY=$(kubectl get configmap "${CONFIGMAP_NAME}" -n "${NAMESPACE}" -o jsonpath='{.data.API_KEY}') + + if [ -z "${API_KEY}" ]; then + echo "UUID not found in ConfigMap, generating new one..." + API_KEY=$(cat /proc/sys/kernel/random/uuid) + kubectl patch configmap "${CONFIGMAP_NAME}" -n "${NAMESPACE}" --type merge -p "{\"data\":{\"API_KEY\":\"${API_KEY}\"}}" + else + echo "Using existing UUID from ConfigMap" + fi + else + echo "ConfigMap does not exist, creating new one..." + API_KEY=$(cat /proc/sys/kernel/random/uuid) + kubectl create configmap "${CONFIGMAP_NAME}" -n "${NAMESPACE}" \ + --from-literal=API_KEY="${API_KEY}" \ + --from-literal=NODE_NAME="${NODE_NAME}" + fi + + # Save UUID and node info to shared volume for the main container + echo -n "${API_KEY}" > /shared/api-key + echo -n "${NODE_NAME}" > /shared/node-name + echo -n "${CONFIGMAP_NAME}" > /shared/configmap-name + echo "UUID initialized: ${API_KEY}" + echo "Node name: ${NODE_NAME}" + echo "ConfigMap: ${CONFIGMAP_NAME}" + + # Create Certificate for this node using DNS name from label + CERT_NAME="pasarguard-node-${DNS_NAME//./-}" + + echo "Creating Certificate: ${CERT_NAME} for ${DNS_NAME}" + + # Check if Certificate already exists + if ! kubectl get certificate "${CERT_NAME}" -n "${NAMESPACE}" &>/dev/null; then + echo "Certificate does not exist, creating..." + cat </dev/null; then + echo "Certificate secret is ready!" + break + fi + echo "Waiting for certificate... ($i/600)" + sleep 1 + done + + if ! kubectl get secret "${CERT_NAME}-tls" -n "${NAMESPACE}" &>/dev/null; then + echo "WARNING: Certificate secret not ready after 600 seconds" + else + # Extract certificate and key from secret to shared volume + echo "Extracting certificate and key..." + kubectl get secret "${CERT_NAME}-tls" -n "${NAMESPACE}" -o jsonpath='{.data.tls\.crt}' | base64 -d > /shared/tls.crt + kubectl get secret "${CERT_NAME}-tls" -n "${NAMESPACE}" -o jsonpath='{.data.tls\.key}' | base64 -d > /shared/tls.key + echo "Certificate and key extracted successfully." + cat /shared/tls.crt + fi + + # Create individual Service and Endpoints for this node + # Take only first part of node name before first dot + NODE_SHORT_NAME="${NODE_NAME%%.*}" + SERVICE_NAME="${NODE_SHORT_NAME}" + + # Get node internal IP (take only first IP if multiple) + NODE_IP=$(kubectl get node "${NODE_NAME}" -o jsonpath='{.status.addresses[?(@.type=="InternalIP")].address}' | awk '{print $1}') + + echo "Creating Service: ${SERVICE_NAME} for node ${NODE_NAME} (short: ${NODE_SHORT_NAME}) with IP ${NODE_IP}" + + # Create Service without selector + cat < ${NODE_IP}:62050" + + exporter-start.sh: | + #!/bin/sh + # Install required tools + apk add --no-cache wget curl iproute2-ss bash + + # Download v2ray-exporter + echo "Downloading v2ray-exporter..." + wget -O /tmp/v2ray-exporter https://github.com/wi1dcard/v2ray-exporter/releases/latest/download/v2ray-exporter_linux_amd64 + mv /tmp/v2ray-exporter /usr/local/bin/v2ray-exporter + chmod +x /usr/local/bin/v2ray-exporter + + # Wait for xray API port file from pasarguard-node container + echo "Waiting for xray API port file..." + while true; do + if [ -f /shared/xray-api-port ]; then + API_PORT=$(cat /shared/xray-api-port) + if [ -n "$API_PORT" ]; then + echo "Got xray API port from shared volume: $API_PORT" + + # Verify the port is working + if curl -s -o /dev/null -w "%{http_code}" --max-time 2 "127.0.0.1:$API_PORT" 2>&1 | grep -q "Received HTTP/0.9"; then + echo "Verified API port: $API_PORT" + break + else + echo "Port verification failed, waiting..." + fi + fi + fi + echo "Waiting for valid xray API port... retrying in 5 seconds" + sleep 5 + done + + # Start exporter + echo "Starting v2ray-exporter with endpoint 127.0.0.1:$API_PORT" + exec /usr/local/bin/v2ray-exporter --v2ray-endpoint "127.0.0.1:$API_PORT" --listen ":9550" + + pasarguard-start.sh: | + #!/bin/sh + # Read API_KEY from shared volume created by init container + if [ -f /shared/api-key ]; then + export API_KEY=$(cat /shared/api-key) + echo "Loaded API_KEY from shared volume" + else + echo "WARNING: API_KEY file not found, using default" + fi + + cd /app + + # Start main process in background + ./main & + MAIN_PID=$! + + # Wait a bit for xray to start + sleep 10 + + # Find xray API port and save to shared volume + echo "Looking for xray API port..." + for i in {1..60}; do + API_PORT=$(netstat -tlpn | grep xray | grep 127.0.0.1 | awk '{print $4}' | cut -d: -f2 | head -1) + if [ -n "$API_PORT" ]; then + echo "Found xray API port: $API_PORT" + echo -n "$API_PORT" > /shared/xray-api-port + break + fi + echo "Waiting for xray API port... ($i/60)" + sleep 1 + done + + # Continue running main process + wait $MAIN_PID diff --git a/k8s/apps/pasarguard/daemonset.yaml b/k8s/apps/pasarguard/daemonset.yaml index 0bd5044..026fd71 100644 --- a/k8s/apps/pasarguard/daemonset.yaml +++ b/k8s/apps/pasarguard/daemonset.yaml @@ -105,204 +105,19 @@ spec: fieldPath: spec.nodeName command: - /bin/bash - - -c - - | - set -e - echo "Started" - # NODE_NAME is already set via environment variable - NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace) - - # Get DNS name from node label xray-node-address - DNS_NAME=$(kubectl get node "${NODE_NAME}" -o jsonpath='{.metadata.labels.xray-node-address}') - - if [ -z "${DNS_NAME}" ]; then - echo "ERROR: Node ${NODE_NAME} does not have label 'xray-node-address'" - exit 1 - fi - - echo "Node: ${NODE_NAME}" - echo "DNS Name from label: ${DNS_NAME}" - - # Use DNS name for ConfigMap name to ensure uniqueness - CONFIGMAP_NAME="node-uuid-${DNS_NAME//./-}" - - echo "Checking ConfigMap: ${CONFIGMAP_NAME}" - - # Check if ConfigMap exists and get UUID - if kubectl get configmap "${CONFIGMAP_NAME}" -n "${NAMESPACE}" &>/dev/null; then - echo "ConfigMap exists, reading UUID..." - API_KEY=$(kubectl get configmap "${CONFIGMAP_NAME}" -n "${NAMESPACE}" -o jsonpath='{.data.API_KEY}') - - if [ -z "${API_KEY}" ]; then - echo "UUID not found in ConfigMap, generating new one..." - API_KEY=$(cat /proc/sys/kernel/random/uuid) - kubectl patch configmap "${CONFIGMAP_NAME}" -n "${NAMESPACE}" --type merge -p "{\"data\":{\"API_KEY\":\"${API_KEY}\"}}" - else - echo "Using existing UUID from ConfigMap" - fi - else - echo "ConfigMap does not exist, creating new one..." - API_KEY=$(cat /proc/sys/kernel/random/uuid) - kubectl create configmap "${CONFIGMAP_NAME}" -n "${NAMESPACE}" \ - --from-literal=API_KEY="${API_KEY}" \ - --from-literal=NODE_NAME="${NODE_NAME}" - fi - - # Save UUID and node info to shared volume for the main container - echo -n "${API_KEY}" > /shared/api-key - echo -n "${NODE_NAME}" > /shared/node-name - echo -n "${CONFIGMAP_NAME}" > /shared/configmap-name - echo "UUID initialized: ${API_KEY}" - echo "Node name: ${NODE_NAME}" - echo "ConfigMap: ${CONFIGMAP_NAME}" - - # Create Certificate for this node using DNS name from label - CERT_NAME="pasarguard-node-${DNS_NAME//./-}" - - echo "Creating Certificate: ${CERT_NAME} for ${DNS_NAME}" - - # Check if Certificate already exists - if ! kubectl get certificate "${CERT_NAME}" -n "${NAMESPACE}" &>/dev/null; then - echo "Certificate does not exist, creating..." - cat </dev/null; then - echo "Certificate secret is ready!" - break - fi - echo "Waiting for certificate... ($i/600)" - sleep 1 - done - - if ! kubectl get secret "${CERT_NAME}-tls" -n "${NAMESPACE}" &>/dev/null; then - echo "WARNING: Certificate secret not ready after 600 seconds" - else - # Extract certificate and key from secret to shared volume - echo "Extracting certificate and key..." - kubectl get secret "${CERT_NAME}-tls" -n "${NAMESPACE}" -o jsonpath='{.data.tls\.crt}' | base64 -d > /shared/tls.crt - kubectl get secret "${CERT_NAME}-tls" -n "${NAMESPACE}" -o jsonpath='{.data.tls\.key}' | base64 -d > /shared/tls.key - echo "Certificate and key extracted successfully." - cat /shared/tls.crt - fi - - # Create individual Service and Endpoints for this node - # Take only first part of node name before first dot - NODE_SHORT_NAME="${NODE_NAME%%.*}" - SERVICE_NAME="${NODE_SHORT_NAME}" - - # Get node internal IP (take only first IP if multiple) - NODE_IP=$(kubectl get node "${NODE_NAME}" -o jsonpath='{.status.addresses[?(@.type=="InternalIP")].address}' | awk '{print $1}') - - echo "Creating Service: ${SERVICE_NAME} for node ${NODE_NAME} (short: ${NODE_SHORT_NAME}) with IP ${NODE_IP}" - - # Create Service without selector - cat < ${NODE_IP}:62050" + - /scripts/init-uuid.sh volumeMounts: - name: shared-data mountPath: /shared + - name: scripts + mountPath: /scripts containers: - name: xray-exporter image: alpine:3.18 imagePullPolicy: IfNotPresent command: - /bin/sh - - -c - - | - # Install required tools - apk add --no-cache wget curl iproute2-ss bash - - # Download v2ray-exporter - echo "Downloading v2ray-exporter..." - wget -O /tmp/v2ray-exporter https://github.com/wi1dcard/v2ray-exporter/releases/latest/download/v2ray-exporter_linux_amd64 - mv /tmp/v2ray-exporter /usr/local/bin/v2ray-exporter - chmod +x /usr/local/bin/v2ray-exporter - - # Wait for xray API port file from pasarguard-node container - echo "Waiting for xray API port file..." - while true; do - if [ -f /shared/xray-api-port ]; then - API_PORT=$(cat /shared/xray-api-port) - if [ -n "$API_PORT" ]; then - echo "Got xray API port from shared volume: $API_PORT" - - # Verify the port is working - if curl -s -o /dev/null -w "%{http_code}" --max-time 2 "127.0.0.1:$API_PORT" 2>&1 | grep -q "Received HTTP/0.9"; then - echo "Verified API port: $API_PORT" - break - else - echo "Port verification failed, waiting..." - fi - fi - fi - echo "Waiting for valid xray API port... retrying in 5 seconds" - sleep 5 - done - - # Start exporter - echo "Starting v2ray-exporter with endpoint 127.0.0.1:$API_PORT" - exec /usr/local/bin/v2ray-exporter --v2ray-endpoint "127.0.0.1:$API_PORT" --listen ":9550" + - /scripts/exporter-start.sh ports: - name: metrics containerPort: 9550 @@ -334,45 +149,14 @@ spec: - name: shared-data mountPath: /shared readOnly: true + - name: scripts + mountPath: /scripts - name: pasarguard-node image: 'pasarguard/node:v0.1.1' imagePullPolicy: Always command: - /bin/sh - - -c - - | - # Read API_KEY from shared volume created by init container - if [ -f /shared/api-key ]; then - export API_KEY=$(cat /shared/api-key) - echo "Loaded API_KEY from shared volume" - else - echo "WARNING: API_KEY file not found, using default" - fi - - cd /app - - # Start main process in background - ./main & - MAIN_PID=$! - - # Wait a bit for xray to start - sleep 10 - - # Find xray API port and save to shared volume - echo "Looking for xray API port..." - for i in {1..60}; do - API_PORT=$(ss -tlpn | grep xray | grep 127.0.0.1 | awk '{print $4}' | cut -d: -f2 | head -1) - if [ -n "$API_PORT" ]; then - echo "Found xray API port: $API_PORT" - echo -n "$API_PORT" > /shared/xray-api-port - break - fi - echo "Waiting for xray API port... ($i/60)" - sleep 1 - done - - # Continue running main process - wait $MAIN_PID + - /scripts/pasarguard-start.sh ports: - name: api containerPort: 62050 @@ -425,6 +209,12 @@ spec: - name: shared-data mountPath: /shared readOnly: false + - name: scripts + mountPath: /scripts volumes: - name: shared-data emptyDir: {} + - name: scripts + configMap: + name: pasarguard-scripts + defaultMode: 0755 diff --git a/k8s/apps/pasarguard/kustomization.yaml b/k8s/apps/pasarguard/kustomization.yaml index b37b057..fb33207 100644 --- a/k8s/apps/pasarguard/kustomization.yaml +++ b/k8s/apps/pasarguard/kustomization.yaml @@ -7,5 +7,6 @@ resources: - ./deployment.yaml - ./daemonset.yaml - ./certificate.yaml + - ./configmap-scripts.yaml