Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[bitnami/mongodb] Simplify and fix externalAccess configuration #25397

Merged
merged 15 commits into from
May 10, 2024

Conversation

fmulero
Copy link
Collaborator

@fmulero fmulero commented Apr 25, 2024

Description of the change

Allow the use of external certificates signed for external names. Current chart requires several internal names and IPs signed in the certificates provided by the user. That restriction makes almost impossible the use of this chart with external names and TLS enabled.

Benefits

Allow the use of external certificates and names in MongoDB chart.

Possible drawbacks

None

Applicable issues

Additional information

These changes were tested in the following scenario:

  1. Empty cluster created with k3d:
$ k3d cluster create
  1. Certificates and secrets have been created with following script:
#!/bin/bash
if [[ ! -f  ca.crt ]]; then
  openssl genrsa -out ca.key 2048
  openssl req -x509 -new -nodes -key ca.key -subj "/CN=example.com" -sha256 -days 1024 -out ca.crt
fi

for i in 0 1 arbiter; do
  if [[ ! -f "mongodb-${i}.crt" ]]; then
    openssl genrsa -out "mongodb-${i}.key" 2048
    openssl req -new -key "mongodb-${i}.key" -subj "/CN=mongodb-${i}.example.com" -out "mongodb-${i}.csr"
    openssl x509 -req -in "mongodb-${i}.csr" -CA ca.crt -CAkey ca.key -CAcreateserial -out "mongodb-${i}.crt" -days 1024 -sha256
  fi
  kubectl create secret tls "mongodb-${i}-cert"  --cert="mongodb-${i}.crt" --key="mongodb-${i}.key"
  kubectl patch secret "mongodb-${i}-cert" -p="{\"data\":{\"ca.crt\": \"$(cat ca.crt | base64 -w0 )\"}}"
done
  1. To avoid issues with name resolution this configuration has been added to the coredns configmap:
rewrite name mongodb-0.example.com mongodb-0.mongodb-headless.default.svc.cluster.local
rewrite name mongodb-1.example.com mongodb-1.mongodb-headless.default.svc.cluster.local
  1. Values used:
architecture: replicaset
replicaCount: 2
tls:
  enabled: true
  autoGenerated: false
  replicaset:
    existingSecrets:
      - mongodb-0-cert
      - mongodb-1-cert
  arbiter:
    existingSecret: mongodb-arbiter-cert
externalAccess:
  enabled: true
  service:
    loadBalancerIPs:
      - 10.10.0.3
      - 10.10.0.4
    annotationsList:
      - external-dns.alpha.kubernetes.io/hostname: mongodb-0.example.com
      - external-dns.alpha.kubernetes.io/hostname: mongodb-1.example.com
  publicNames:
    - mongodb-0.example.com
    - mongodb-1.example.com

Checklist

  • Chart version bumped in Chart.yaml according to semver. This is not necessary when the changes only affect README.md files.
  • Variables are documented in the values.yaml and added to the README.md using readme-generator-for-helm
  • Title of the pull request follows this pattern [bitnami/<name_of_the_chart>] Descriptive title
  • All commits signed off and in agreement of Developer Certificate of Origin (DCO)

@bitnami-bot bitnami-bot added the verify Execute verification workflow for these changes label Apr 25, 2024
@github-actions github-actions bot requested a review from rafariossaa April 25, 2024 17:20
@rrileyca
Copy link
Contributor

Hey @fmulero thanks for looking into this.

Does this work? One of the issues is that Mongo will see the external DNS name in the Replica config (which can be seen in mongosh with rs.config()) and that won't match its hostname, so it will think it's not in the cluster. Have you tested this?

@fmulero
Copy link
Collaborator Author

fmulero commented Apr 26, 2024

Hey @fmulero thanks for looking into this.

Does this work? One of the issues is that Mongo will see the external DNS name in the Replica config (which can be seen in mongosh with rs.config()) and that won't match its hostname, so it will think it's not in the cluster. Have you tested this?

At the moment I didn't face that issue, maybe because I am changing my coredns config to rewrite mongodb-0.example.com to mongodb-0.mongodb-headless.default.svc.cluster.local

@fmulero
Copy link
Collaborator Author

fmulero commented May 3, 2024

Hi @rrileyca, I think I reproduced the problem you mentioned. To fix it I configured the cluster using the external names and I added an init container to ensure that we can resolve the external name before init the cluster.

Signed-off-by: Fran Mulero <[email protected]>
@fmulero fmulero marked this pull request as ready for review May 6, 2024 14:45
@rrileyca
Copy link
Contributor

rrileyca commented May 6, 2024

Hey @fmulero, thanks this is defnitely a useful feature.

Does it work without the coreDNS edits in the kubernetes cluster though? I think the external DNS name has to match the hostname of the Pod, and failing a hostname match it does a DNS lookup and tries to match the IP's of the Replicas to its own IP. I don't see any changes to the hostname of the Pod, just the services.

The reason changing the coreDNS config works (I believe) is because you can put the public DNS names like mongo-1.mydns.com in the Mongo ReplicaSet config, which coreDNS then translates to the service name like mongodb.svc.cluster.local and resolves the Pod IP. Mongo sees that IP address matches its local interface address and then assumes it is part of the cluster.

I think the problem here is that when you resolve the public DNS name of a node, it will resolve to the Loadbalancer IP address which is not the Pod IP. Mongo will not think it is part of the cluster in this case.

Does your PR assume that you have a DNS name that always translates to the Pod IP? If so, how do you keep this DNS entry up to date? I've only used external-dns for Loadbalancers and Ingresses.

@fmulero
Copy link
Collaborator Author

fmulero commented May 7, 2024

HI @rrileyca thanks for taking care of this. I've tested it following these steps:

  1. Create the certificates with the script described in the description.
  2. Run a regular installation with the values below:
architecture: replicaset
replicaCount: 2
tls:
  enabled: true
  autoGenerated: false
  replicaset:
    existingSecrets:
      - mongodb-0-cert
      - mongodb-1-cert
  arbiter:
    existingSecret: mongodb-arbiter-cert
externalAccess:
  enabled: true
  service:
    type: LoadBalancer
    publicNames:
      - 'mongodb-0.example.com'
      - 'mongodb-1.example.com'

That will create 2 external services and the pods will wait for the mongodb-0.example.com name resolution.

  1. Once the external services have their external ip addresses we can upgrade the deployment adding hostAliases to resolve the external names:
architecture: replicaset
replicaCount: 2
tls:
  enabled: true
  autoGenerated: false
  replicaset:
    existingSecrets:
      - mongodb-0-cert
      - mongodb-1-cert
  arbiter:
    existingSecret: mongodb-arbiter-cert
externalAccess:
  enabled: true
  service:
    type: LoadBalancer
    publicNames:
      - 'mongodb-0.example.com'
      - 'mongodb-1.example.com'
hostAliases: &aliases
  - ip: 35.243.236.68
    hostnames:
      - mongodb-0.example.com
  - ip: 34.75.99.90
    hostnames:
      - mongodb-1.example.com
arbiter:
  hostAliases: *aliases
  1. At this point our pods are stuck waiting for name resolution. In this case, we have changed the StatefulSet adding the hostAliases, we have to remove old pods.
$ kubectl delete pods mongodb-0 mongodb-arbiter-0
pod "mongodb-0" deleted
pod "mongodb-arbiter-0" deleted
  1. New pods start running and get ready. Now if we run the following commands we can see how mongodb-0 is primary and mongodb-1 is secondary:
$ kubectl exec -it mongodb-0 -c mongodb -- mongosh --tls --tlsCertificateKeyFile=/certs/mongodb.pem --tlsCAFile=/certs/mongodb-ca-cert --tlsAllowInvalidHostnames --port $MONGODB_PORT_NUMBER  --eval "db.hello().isWritablePrimary"
true
$ kubectl exec -it mongodb-0 -c mongodb -- mongosh --tls --tlsCertificateKeyFile=/certs/mongodb.pem --tlsCAFile=/certs/mongodb-ca-cert --tlsAllowInvalidHostnames --port $MONGODB_PORT_NUMBER  --eval "db.hello().secondary"
false
$ kubectl exec -it mongodb-1 -c mongodb -- mongosh --tls --tlsCertificateKeyFile=/certs/mongodb.pem --tlsCAFile=/certs/mongodb-ca-cert --tlsAllowInvalidHostnames --port $MONGODB_PORT_NUMBER  --eval "db.hello().isWritablePrimary"
false
$ kubectl exec -it mongodb-1 -c mongodb -- mongosh --tls --tlsCertificateKeyFile=/certs/mongodb.pem --tlsCAFile=/certs/mongodb-ca-cert --tlsAllowInvalidHostnames --port $MONGODB_PORT_NUMBER  --eval "db.hello().secondary"
true

From my understanding everything looks good.

rafariossaa
rafariossaa previously approved these changes May 9, 2024
Copy link
Contributor

@rafariossaa rafariossaa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

…le: ENOENT: no such file or directory, mkdir '/.mongodb/mongosh'

Signed-off-by: Fran Mulero <[email protected]>
@rrileyca
Copy link
Contributor

rrileyca commented May 9, 2024

thanks @fmulero. Should those instructions regarding the hostAliases be added to the README? As I understand it, there is no way to deploy using public names in a single helm install. You need to deploy it, let the IPs be allocated, and then add the hostAliases and run a helm update afterward.

@fmulero
Copy link
Collaborator Author

fmulero commented May 10, 2024

I've just added a note about hostAliases. From my understanding that is useful in testing environments. In the real world, developers or SREs should be able to update their DNS records, using external-dns (the chart allows it) or manually configuring the DNS server records. In that case the pods will wait for name resolution and then they'll continue with the startup process.

@fmulero fmulero enabled auto-merge (squash) May 10, 2024 14:07
@fmulero fmulero merged commit 90b73a8 into bitnami:main May 10, 2024
8 checks passed
@fmulero fmulero deleted the feature/mongoedb-public-names branch May 10, 2024 14:49
clarifai-fmarceau pushed a commit to clarifai-fmarceau/bitnami-charts that referenced this pull request May 30, 2024
…ami#25397)

* [bitnami/mongodb] Simplify and fix externalAccess configuration

Signed-off-by: Fran Mulero <[email protected]>

* Version bump

Signed-off-by: Fran Mulero <[email protected]>

* Update README.md with readme-generator-for-helm

Signed-off-by: Bitnami Containers <[email protected]>

* Change validations

Signed-off-by: Fran Mulero <[email protected]>

* Create init container to wait for dns resolution

Signed-off-by: Fran Mulero <[email protected]>

* Update README.md with readme-generator-for-helm

Signed-off-by: Bitnami Containers <[email protected]>

* Amend MONGODB_INITIAL_PRIMARY_HOST on arbiter statefulset

Signed-off-by: Fran Mulero <[email protected]>

* Add documentation

Signed-off-by: Fran Mulero <[email protected]>

* Fix Chart copyright and little fix on replicaset statefulset

Signed-off-by: Fran Mulero <[email protected]>

* Remove local addresses and IPs from certificate definition

Signed-off-by: Fran Mulero <[email protected]>

* Add mongosh home directory to avoid this message: Could not access file: ENOENT: no such file or directory, mkdir '/.mongodb/mongosh'

Signed-off-by: Fran Mulero <[email protected]>

* Add README note about hostAliases

Signed-off-by: Fran Mulero <[email protected]>

---------

Signed-off-by: Fran Mulero <[email protected]>
Signed-off-by: Bitnami Containers <[email protected]>
Co-authored-by: Bitnami Containers <[email protected]>
Signed-off-by: Francois Marceau <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bitnami mongodb solved verify Execute verification workflow for these changes
Projects
None yet
5 participants