jhipster / generator-jhipster

JHipster is a development platform to quickly generate, develop, & deploy modern web applications & microservice architectures.
https://www.jhipster.tech
Apache License 2.0
21.54k stars 4.02k forks source link

Kubernetes JDL is invalid after upgrading to 7.9.2 #19419

Closed mraible closed 2 years ago

mraible commented 2 years ago
Overview of the issue

I have the following JDL for Kubernetes (from reactive-mf.jdl):

deployment {
  deploymentType kubernetes
  appsFolders [gateway, blog, store]
  clusteredDbApps [store]
  kubernetesNamespace demo
  serviceDiscoveryType eureka
  dockerRepositoryName "mraible"
}

When I run ./kubectl-apply.sh on the generated kubernetes folder, there's an error:

The StatefulSet "store-mongodb" is invalid: spec: Forbidden: updates to statefulset spec for fields 
other than 'replicas', 'template', 'updateStrategy', 'persistentVolumeClaimRetentionPolicy' and 
'minReadySeconds' are forbidden
Motivation for or Use Case

I think I've tried this with previous versions and there was no error.

Reproduce the error
# clone and npm link main branch
jhipster jdl reactive-mf --client-framework angularX
# build Docker containers
cd kubernetes && ./kubectl-apply.sh -f
JHipster Version(s)

main branch

ubaid4j commented 2 years ago

Hi @mraible, @vishal423 can you please assign this issue to me? I'd like to fix this issue on my weekend. Thanks

mraible commented 2 years ago

@DanielFran Can you please add a new milestone for the next release (e.g., 7.9.3)? That way we can add issues like this one that we want to be fixed in it.

DanielFran commented 2 years ago

@mraible Yes, will do it today

DanielFran commented 2 years ago

@mraible milestone 7.9.3 created

mraible commented 2 years ago

Thanks!

mraible commented 2 years ago

@saturnism Any idea how to fix this? Here's what is generated in the the store-mongodb.yml file:

apiVersion: v1
kind: ConfigMap
metadata:
  namespace: demo
  name: store-mongodb-config
data:
  mongod.conf: |
    net:
      port: 27017
    replication:
      replSetName: rs0
    storage:
      dbPath: /data/db
---
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: demo
  name: store-mongodb-init
data:
  on-start.sh: |
    script_name=${0##*/}

    log() {
        local msg="$1"
        local timestamp
        timestamp=$(date --iso-8601=ns)
        echo "[$timestamp] [$script_name] $msg" >> /work-dir/log.txt
    }

    shutdown_mongo() {
        if [[ $# -eq 1 ]]; then
            args="timeoutSecs: $1"
        else
            args='force: true'
        fi
        log "Shutting down MongoDB ($args)..."
        mongo admin "${admin_creds[@]}" "${ssl_args[@]}" --eval "db.shutdownServer({$args})"
    }

    my_hostname=$(hostname)
    log "Bootstrapping MongoDB replica set member: $my_hostname"

    log "Reading standard input..."
    while read -ra line; do
        if [[ "${line}" == *"${my_hostname}"* ]]; then
            service_name="$line"
            continue
        fi
        peers=("${peers[@]}" "$line")
    done

    # Generate the ca cert
    ca_crt=/data/configdb/tls.crt
    if [ -f "$ca_crt"  ]; then
        log "Generating certificate"
        ca_key=/data/configdb/tls.key
        pem=/work-dir/mongo.pem
        ssl_args=(--ssl --sslCAFile "$ca_crt" --sslPEMKeyFile "$pem")

    # Move into /work-dir
    pushd /work-dir

    cat >openssl.cnf <<EOL
    [req]
    req_extensions = v3_req
    distinguished_name = req_distinguished_name
    [req_distinguished_name]
    [ v3_req ]
    basicConstraints = CA:FALSE
    keyUsage = nonRepudiation, digitalSignature, keyEncipherment
    subjectAltName = @alt_names
    [alt_names]
    DNS.1 = $(echo -n "$my_hostname" | sed s/-[0-9]*$//)
    DNS.2 = $my_hostname
    DNS.3 = $service_name
    DNS.4 = localhost
    DNS.5 = 127.0.0.1
    EOL

        # Generate the certs
        openssl genrsa -out mongo.key 2048
        openssl req -new -key mongo.key -out mongo.csr -subj "/CN=$my_hostname" -config openssl.cnf
        openssl x509 -req -in mongo.csr \
            -CA "$ca_crt" -CAkey "$ca_key" -CAcreateserial \
            -out mongo.crt -days 3650 -extensions v3_req -extfile openssl.cnf

        rm mongo.csr
        cat mongo.crt mongo.key > $pem
        rm mongo.key mongo.crt
    fi

    log "Peers: ${peers[*]}"

    log "Starting a MongoDB instance..."
    mongod --config /data/configdb/mongod.conf --dbpath="$DATA_PATH" --replSet="$REPLICA_SET" --port=$PORT "${auth_args[@]}" --bind_ip=0.0.0.0 >> /work-dir/log.txt 2>&1 &

    log "Waiting for MongoDB to be ready..."
    until mongo "${ssl_args[@]}" --eval "db.adminCommand('ping')"; do
        log "Retrying..."
        sleep 2
    done

    log "Initialized."

    # try to find a master and add yourself to its replica set.
    for peer in "${peers[@]}"; do
        if mongo admin --host "$peer" "${admin_creds[@]}" "${ssl_args[@]}" --eval "rs.isMaster()" | grep '"ismaster" : true'; then
            log "Found master: $peer"
            log "Adding myself ($service_name) to replica set..."
            if mongo admin --host "$peer" "${admin_creds[@]}" "${ssl_args[@]}" --eval "rs.add('$service_name')" | grep 'Quorum check failed'; then
                log 'Quorum check failed, unable to join replicaset. Exiting prematurely.'
                shutdown_mongo
                exit 1
            fi

            sleep 3

            log 'Waiting for replica to reach SECONDARY state...'
            until printf '.' && [[ $(mongo admin "${admin_creds[@]}" "${ssl_args[@]}" --quiet --eval "rs.status().myState") == '2' ]]; do
                sleep 1
            done

            log '✓ Replica reached SECONDARY state.'

            shutdown_mongo "60"
            log "Good bye."
            exit 0
        fi
    done

    # else initiate a replica set with yourself.
    if mongo "${ssl_args[@]}" --eval "rs.status()" | grep "no replset config has been received"; then
        log "Initiating a new replica set with myself ($service_name)..."
        mongo "${ssl_args[@]}" --eval "rs.initiate({'_id': '$REPLICA_SET', 'members': [{'_id': 0, 'host': '$service_name'}]})"

        sleep 3

        log 'Waiting for replica to reach PRIMARY state...'
        until printf '.' && [[ $(mongo "${ssl_args[@]}" --quiet --eval "rs.status().myState") == '1' ]]; do
            sleep 1
        done

        log '✓ Replica reached PRIMARY state.'

        log "Done."
    fi

    shutdown_mongo
    log "Good bye."
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: store-mongodb
  namespace: demo
spec:
  serviceName: store-mongodb
  replicas: 3
  selector:
    matchLabels:
      app: store-mongodb
  template:
    metadata:
      labels:
        app: store-mongodb
    spec:
      initContainers:
        - name: config
          image: busybox
          command:
            - "sh"
          args:
            - "-c"
            - |
              set -e
              set -x
              cp /configdb-readonly/mongod.conf /data/configdb/mongod.conf
          volumeMounts:
            - name: workdir
              mountPath: /work-dir
            - name: config
              mountPath: /configdb-readonly
            - name: configdir
              mountPath: /data/configdb
        - name: install
          image: "k8s.gcr.io/mongodb-install:0.6"
          args:
            - --work-dir=/work-dir
          imagePullPolicy: "IfNotPresent"
          volumeMounts:
            - name: workdir
              mountPath: /work-dir
        - name: boot
          image: mongo:4.4.14
          command:
            - /work-dir/peer-finder
          args:
            - -on-start=/init/on-start.sh
            - "-service=store-mongodb"
          imagePullPolicy: "IfNotPresent"
          env:
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: metadata.namespace
            - name: REPLICA_SET
              value: rs0
            - name: DATA_PATH
              value: /data/db
            - name: PORT
              value: "27017"
          volumeMounts:
            - name: workdir
              mountPath: /work-dir
            - name: init
              mountPath: /init
            - name: configdir
              mountPath: /data/configdb
            - name: datadir
              mountPath: /data/db
      containers:
        - name: mongodb
          image: mongo:4.4.14
          imagePullPolicy: "IfNotPresent"
          env:
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: metadata.namespace
            - name: REPLICA_SET
              value: rs0
            - name: DATA_PATH
              value: /data/db
            - name: PORT
              value: "27017"
          ports:
            - name: peer
              containerPort: 27017
          command:
            - mongod
          args:
            - --config=/data/configdb/mongod.conf
            - --dbpath=$(DATA_PATH)
            - --replSet=$(REPLICA_SET)
            - --port=$(PORT)
            - --bind_ip=0.0.0.0
          livenessProbe:
            exec:
              command:
                - mongo
                - --eval
                - "db.adminCommand('ping')"
            initialDelaySeconds: 30
            timeoutSeconds: 5
            failureThreshold: 3
            periodSeconds: 10
            successThreshold: 1
          readinessProbe:
            exec:
              command:
                - mongo
                - --eval
                - "db.adminCommand('ping')"
            initialDelaySeconds: 5
            timeoutSeconds: 1
            failureThreshold: 3
            periodSeconds: 10
            successThreshold: 1
          volumeMounts:
            - name: datadir
              mountPath: /data/db
            - name: configdir
              mountPath: /data/configdb
            - name: workdir
              mountPath: /work-dir
          resources:
            requests:
              memory: "512Mi"
              cpu: "500m"
            limits:
              memory: "1Gi"
              cpu: "1"
      volumes:
        - name: config
          configMap:
            name: store-mongodb-config
        - name: workdir
          emptyDir: {}
        - name: init
          configMap:
            defaultMode: 0755
            name: store-mongodb-init
        - name: configdir
          emptyDir: {}
        - name: datadir
          emptyDir: {}
---
# Headless service for DNS record
apiVersion: v1
kind: Service
metadata:
  name: store-mongodb
  namespace: demo
spec:
  type: ClusterIP
  clusterIP: None
  publishNotReadyAddresses: true
  ports:
    - name: peer
      port: 27017
  selector:
    app: store-mongodb

Error is:

The StatefulSet "store-mongodb" is invalid: spec: Forbidden: updates to statefulset spec for fields 
other than 'replicas', 'template', 'updateStrategy', 'persistentVolumeClaimRetentionPolicy' and 
'minReadySeconds' are forbidden
deepu105 commented 2 years ago

@mraible could it be you applied this on an existing cluster?

mraible commented 2 years ago

I experienced it with minikube. If I run minikube delete and start minikube again with minikube start, it works! Thanks for this tip.

the error is normal if you apply a stateful set with same name as an existing one in cluster

I'll close this issue.