<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Mongodb on ege.dev</title>
    <link>https://ege.dev/tags/mongodb/</link>
    <description>Hello. I&#39;m Ege.</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <copyright>&#169; 2026 ege.dev</copyright>
    <lastBuildDate>Tue, 19 May 2026 18:15:35 +0000</lastBuildDate>
    <atom:link href="https://ege.dev/tags/mongodb/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Authenticating Your Clients to Mongodb on Kubernetes Using X509 Certificates</title>
      <link>https://ege.dev/entries/2022/02/authenticating-your-clients-to-mongodb-on-kubernetes-using-x509-certificates/</link>
      <pubDate>Sun, 13 Feb 2022 20:42:57 +0300</pubDate>
      <guid isPermaLink="false">https://ege.dev/entries/2022/02/authenticating-your-clients-to-mongodb-on-kubernetes-using-x509-certificates/</guid>
      <description>&lt;p&gt;Managing database users and their passwords can be a hassle. Sometimes, they
could even wait in various configuration files, hardcoded. Using certificates
can help you avoid the toil of managing, rotating, and securing user passwords,
so let’s see how to have x509 certificate authentication with the &lt;a href=&#34;https://www.percona.com/doc/kubernetes-operator-for-psmongodb/index.html&#34;&gt;Percona
Server for MongoDB
Operator&lt;/a&gt;
and cert-manager.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cert-manager.io/&#34;&gt;cert-manager&lt;/a&gt; is our recommended way to manage TLS
certificates on Kubernetes clusters. The operator is already integrated with it
to generate certificates for TLS and cluster member authentication. We’re going
to leverage cert-manager APIs to generate valid certificates for MongoDB
clients.&lt;/p&gt;
&lt;p&gt;There are rules to follow to have a valid certificate for user authentication:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A single Certificate Authority (CA) MUST sign all certificates.&lt;/li&gt;
&lt;li&gt;The certificate’s subject MUST be unique.&lt;/li&gt;
&lt;li&gt;The certificate MUST not be expired.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For the complete requirements, check the &lt;a href=&#34;https://docs.mongodb.com/manual/core/security-x.509/#client-certificate-requirements&#34;&gt;MongoDB
docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;creating-valid-certificates-for-clients&#34;&gt;Creating Valid Certificates for Clients&lt;/h2&gt;
&lt;p&gt;Let’s check our current certificates:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl get cert
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NAME                      READY   SECRET                    AGE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cluster1-ssl              True    cluster1-ssl              17h
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cluster1-ssl-internal     True    cluster1-ssl-internal     17h
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The operator configures MongoDB nodes to use &amp;ldquo;cluster1-ssl-internal&amp;rdquo; as the
certificate authority. We’re going to use it to sign the client certificates to
conform to Rule 1.&lt;/p&gt;
&lt;p&gt;First, we need to create an Issuer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl apply -f - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;lt;&amp;lt;EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;apiVersion: cert-manager.io/v1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;kind: Issuer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; name: cluster1-psmdb-x509-ca
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; ca:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;   secretName: cluster1-ssl-internal
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, our certificate:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl apply -f - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;lt;&amp;lt;EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;apiVersion: cert-manager.io/v1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;kind: Certificate
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; name: cluster1-psmdb-egegunes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; secretName: cluster1-psmdb-egegunes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; isCA: false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; commonName: egegunes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; subject:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;   organizations:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;     - percona
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;   organizationalUnits:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;     - cloud
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; usages:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;   - digital signature
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;   - client auth
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt; issuerRef:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;   name: cluster1-psmdb-x509-ca
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;   kind: Issuer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;   group: cert-manager.io
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &amp;ldquo;usages&amp;rdquo; field is important. You shouldn’t touch its values. You can change
the &amp;ldquo;subject&amp;rdquo; and &amp;ldquo;commonName&amp;rdquo; fields as you wish. They’re going to construct
the Distinguished Name (DN) and DN will be the username.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl get secret cluster1-psmdb-egegunes -o yaml &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    | yq3 r - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;data.&amp;#34;tls.crt&amp;#34;&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    | base64 -d &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    | openssl x509 -subject -noout
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;subject&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;O &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; percona, OU &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; cloud, CN &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; egegunes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s create the user:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;rs0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;PRIMARY&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;getSiblingDB&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;$external&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;runCommand&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#a6e22e&#34;&gt;createUser&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CN=egegunes,OU=cloud,O=percona&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#a6e22e&#34;&gt;roles&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; [{ &lt;span style=&#34;color:#a6e22e&#34;&gt;role&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;readWrite&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;test&amp;#39;&lt;/span&gt; }]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ok&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;$clusterTime&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;clusterTime&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Timestamp&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1643099623&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;signature&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hash&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BinData&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EdPrmPJqfgRpMEZwGMeKNLdCe10=&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;keyId&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;NumberLong&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;7056790236952526853&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;               }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;operationTime&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Timestamp&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1643099623&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We’re creating the user in the &amp;ldquo;$external&amp;rdquo; database. You need to use
&amp;ldquo;$external&amp;rdquo; as your authentication source. Note that we’re reversing the
subject fields, this is important.&lt;/p&gt;
&lt;h2 id=&#34;authenticating-with-the-certificate&#34;&gt;Authenticating With the Certificate&lt;/h2&gt;
&lt;p&gt;I have created a simple Go application to show how you can use x509
certificates to authenticate. It’s redacted here for brevity:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// ca.crt is mounted from secret/cluster1-ssl
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;caFilePath&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/etc/mongodb-ssl/ca.crt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// tls.pem consists of tls.key and tls.crt, they&amp;#39;re mounted from
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;secret&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;cluster1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;psmdb&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;egegunes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;certKeyFilePath&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/tmp/tls.pem&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;endpoint&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cluster1-rs0.psmdb.svc.cluster.local&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;uri&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sprintf&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mongodb+srv://%s/?tlsCAFile=%s&amp;amp;tlsCertificateKeyFile=%s&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;endpoint&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;caFilePath&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;certKeyFilePath&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;credential&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;options&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Credential&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;AuthMechanism&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;MONGODB-X509&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;AuthSource&lt;/span&gt;:    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;$external&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;opts&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;options&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Client&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;SetAuth&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;credential&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;ApplyURI&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;uri&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;client&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mongo&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Connect&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;opts&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The important part is using &amp;ldquo;MONGODB-X509&amp;rdquo; as the authentication mechanism. We
also need to pass the CA and client certificate in the MongoDB URI.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl logs psmdb-x509-tester-688c989567-rmgxv
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2022/01/25 07:50:09 Connecting to database
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2022/01/25 07:50:09 URI: mongodb+srv://cluster1-rs0.psmdb.svc.cluster.local/?tlsCAFile&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/etc/mongodb-ssl/ca.crt&amp;amp;tlsCertificateKeyFile&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/tmp/tls.pem
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2022/01/25 07:50:09 Username: O&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;percona,OU&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;cloud,CN&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;egegunes
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2022/01/25 07:50:09 Connected to database
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2022/01/25 07:50:09 Successful ping
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can see the complete example in &lt;a href=&#34;https://github.com/egegunes/psmdb-x509-tester&#34;&gt;this
repository&lt;/a&gt;. If you have any
questions, please add a comment or create a topic in the &lt;a href=&#34;http://forums.percona.com/&#34;&gt;Percona
Forums&lt;/a&gt;.&lt;/p&gt;
</description>
      <category>mongodb</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Disaster Recovery for MongoDB on Kubernetes</title>
      <link>https://ege.dev/entries/2021/10/disaster-recovery-for-mongodb-on-kubernetes/</link>
      <pubDate>Fri, 08 Oct 2021 15:10:57 +0300</pubDate>
      <guid isPermaLink="false">https://ege.dev/entries/2021/10/disaster-recovery-for-mongodb-on-kubernetes/</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a joint post with Sergey Pronin.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As per the glossary, Disaster Recovery (DR) protocols are an organization’s
method of regaining access and functionality to its IT infrastructure in events
like a natural disaster, cyber attack, or even business disruptions related to
the COVID-19 pandemic. When we talk about data, storing backups on remote
servers is enough to pass DR compliance checks for some companies. But for
others, Recovery Time Objectives (RTO) and Recovery Point Objectives (RPO) are
extremely tight and require more than just a backup/restore procedure.&lt;/p&gt;
&lt;p&gt;In this blog post, we are going to show you how to set up MongoDB on two
distant Kubernetes clusters with Percona Distribution for MongoDB Operator to
meet the toughest DR requirements.&lt;/p&gt;
&lt;h3 id=&#34;what-to-expect&#34;&gt;What to Expect&lt;/h3&gt;
&lt;p&gt;Here is what we are going to do:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Setup two Kubernetes clusters&lt;/li&gt;
&lt;li&gt;Deploy Percona Distribution for MongoDB Operator on both of them. The
Disaster Recovery site will run a MongoDB cluster in unmanaged mode.&lt;/li&gt;
&lt;li&gt;We are going to simulate the failure and perform a failover to DR site&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the 1.10.0 version of the Operator, we have added the Technology Preview of
the new feature which enables users to deploy unmanaged MongoDB nodes and
connect them to existing Replica Sets.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://ege.dev/images/k8spsmdb-disaster-recovery/blog_mongodr_0.png&#34; alt=&#34;figure-0&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;set-it-all-up&#34;&gt;Set it All Up&lt;/h3&gt;
&lt;p&gt;We are not going to cover the configuration of the Kubernetes clusters, but in
our tests, we relied on two Google Kubernetes Engine (GKE) clusters deployed in
different regions.&lt;/p&gt;
&lt;h3 id=&#34;prepare-main-site&#34;&gt;Prepare Main Site&lt;/h3&gt;
&lt;p&gt;We have shared all the resources for this blog post in this GitHub repo. As a
first step we are going to deploy the operator on the Main site:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ kubectl apply -f bundle.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Deploy the MongoDB managed cluster with &lt;code&gt;cr-main.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ kubectl apply -f cr-main.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It is important to understand that we will need to expose ReplicaSet nodes
through a dedicated service. This includes Config Servers. This is required to
ensure that ReplicaSet nodes on Main and DR can reach each other. So it is like
a full mesh:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://ege.dev/images/k8spsmdb-disaster-recovery/blog_mongodr_1.png&#34; alt=&#34;figure-1&#34;&gt;&lt;/p&gt;
&lt;p&gt;To get there, cr-main.yaml has the following changes:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;spec:
  replsets:
  - rs0:
    expose:
      enabled: true
      exposeType: LoadBalancer
  sharding:
    configsvrReplSet:
      expose:
        enabled: true
        exposeType: LoadBalancer
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We are using the LoadBalancer Kubernetes Service object as it is just simpler
for us, but there are other options – ClusterIP, NodePort. It is also possible
to utilize 3rd party tools like Submariner to implement a private connection.&lt;/p&gt;
&lt;p&gt;If you have an already running MongoDB cluster in Kubernetes, you can expose
the ReplicaSets without downtime by changing these variables.&lt;/p&gt;
&lt;h3 id=&#34;prepare-disaster-recovery-site&#34;&gt;Prepare Disaster Recovery Site&lt;/h3&gt;
&lt;p&gt;The configuration of the Disaster Recovery site could be broken down into the
following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Copy the Secrets from the Main cluster.
&lt;ol&gt;
&lt;li&gt;system users secrets&lt;/li&gt;
&lt;li&gt;SSL keys – both used for external connections and internal replication traffic&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Tune Custom Resource:
&lt;ol&gt;
&lt;li&gt;run nodes in unmanaged mode – Operator does not control replicaset configuration and secrets generation&lt;/li&gt;
&lt;li&gt;expose ReplicaSets (the same way we do it on the Main cluster)&lt;/li&gt;
&lt;li&gt;disable backups – backups can be only taken on the cluster managed by the Operator&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;copy-the-secrets&#34;&gt;Copy the Secrets&lt;/h3&gt;
&lt;p&gt;System user’s credentials are stored by default in my-cluster-name-secrets
Secret object and defined in spec.secrets.users. Apply this secret in the DR
cluster with kubectl apply -f yaml-with-secrets. If you don’t have it in your
source code repository or if you rely on the Operator to generate it, you can
get the secret from Kubernetes itself, remove the unnecessary metadata and
apply.&lt;/p&gt;
&lt;p&gt;On main execute:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ kubectl get secret my-cluster-name-secrets -o yaml &amp;gt; my-cluster-secrets.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now remove the following lines from metadata:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;annotations
creationTimestamp
resourceVersion
selfLink
uid
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Save the file and apply it to the DR cluster.&lt;/p&gt;
&lt;p&gt;The procedure to copy SSL keys is almost the same as for users. The difference
is the names of the Secret objects – they are usually called &amp;lt;CLUSTER_NAME&amp;gt;-ssl
and &amp;lt;CLUSTER_NAME&amp;gt;-ssl-internal. It is also possible to specify them in
secrets.ssl and secrets.sslInternal in the Custom Resource. Copy these two keys
from Main to DR and reference them in the CR.&lt;/p&gt;
&lt;h3 id=&#34;tune-custom-resource&#34;&gt;Tune Custom Resource&lt;/h3&gt;
&lt;p&gt;cr-replica.yaml will have the following changes:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;  secrets:
    users: my-cluster-name-secrets
    ssl: replica-cluster-ssl
    sslInternal: replica-cluster-ssl-internal
 
  replsets:
  - name: rs0
    size: 3
    expose:
      enabled: true
      exposeType: LoadBalancer
 
  sharding:
    enabled: true
    configsvrReplSet:
      size: 3
      expose:
        enabled: true
        exposeType: LoadBalancer
 
  backup:
    enabled: false
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Once the Custom Resource is applied, the services are going to be created. We
will need the IP addresses of each ReplicaSet node to configure the DR site.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ kubectl get services
NAME                  TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)           AGE
replica-cluster-cfg-0    LoadBalancer   10.111.241.213   34.78.119.1       27017:31083/TCP   5m28s
replica-cluster-cfg-1    LoadBalancer   10.111.243.70    35.195.138.253    27017:31957/TCP   4m52s
replica-cluster-cfg-2    LoadBalancer   10.111.246.94    146.148.113.165   27017:30196/TCP   4m6s
...
replica-cluster-rs0-0    LoadBalancer   10.111.241.41    34.79.64.213      27017:31993/TCP   5m28s
replica-cluster-rs0-1    LoadBalancer   10.111.242.158   34.76.238.149     27017:32012/TCP   4m47s
replica-cluster-rs0-2    LoadBalancer   10.111.242.191   35.195.253.107    27017:31209/TCP   4m22s
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;add-external-nodes-to-main&#34;&gt;Add External Nodes to Main&lt;/h3&gt;
&lt;p&gt;At this step, we are going to add unmanaged nodes to the Replica Set on the
Main site. In cr-main.yaml we should add externalNodes under replsets.[] and
sharding.configsvrReplSet:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;  replsets:
  - name: rs0
    externalNodes:
    - host: 34.79.64.213
      priority: 1
      votes: 1
    - host: 34.76.238.149
      priority: 1
      votes: 1
    - host: 35.195.253.107
      priority: 0
      votes: 0
 
  sharding:
    configsvrReplSet:
      externalNodes:
      - host: 34.78.119.1
        priority: 1
        votes: 1
      - host: 35.195.138.253
        priority: 1
        votes: 1
      - host: 146.148.113.165
        priority: 0
        votes: 0
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Please note that we add three nodes, but only two are voters. We do this to
avoid split-brain situations and do not start the primary election if the DR
site is down or there is a network disruption between the Main and DR sites.&lt;/p&gt;
&lt;h3 id=&#34;failover&#34;&gt;Failover&lt;/h3&gt;
&lt;p&gt;Once all the configuration above is applied, the situation will look like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://ege.dev/images/k8spsmdb-disaster-recovery/blog_mongodr_2.png&#34; alt=&#34;figure-2&#34;&gt;&lt;/p&gt;
&lt;p&gt;We have three voters in the main cluster and two voters in the replica cluster.
That means replica nodes won’t have the majority in case of main cluster
failure and they won’t be able to elect a new primary. Therefore we need to
step in and perform a manual failover.&lt;/p&gt;
&lt;p&gt;Let’s kill the main cluster:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;gcloud compute instances list \
    | grep my-main-gke-demo \
    | awk &amp;#39;{print $1}&amp;#39; \
    | xargs gcloud compute instances delete --zone europe-west3-b

gcloud container node-pools delete \
    --zone europe-west3-b \
    --cluster my-main-gke-demo \
    default-pool
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I deleted the nodes and the node pool of the main Kubernetes cluster so now the cluster is in an unhealthy state. Let’s see what mongos on the DR site says when we try to read or write through it:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;% ./psmdb-tester
2021/09/03 18:19:19 Successfully connected and pinged 34.141.3.189:27017
2021/09/03 18:19:40 read failed: (FailedToSatisfyReadPreference) Encountered non-retryable error during query :: caused by :: Could not find host matching read preference { mode: &amp;#34;primary&amp;#34; } for set cfg
2021/09/03 18:19:49 write failed: (FailedToSatisfyReadPreference) Could not find host matching read preference { mode: &amp;#34;primary&amp;#34; } for set cfg
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&#34;https://ege.dev/images/k8spsmdb-disaster-recovery/blog_mongodr_3.png&#34; alt=&#34;figure-3&#34;&gt;&lt;/p&gt;
&lt;p&gt;Normally, we can only alter the replica set configuration from the primary node
but in this kind of situation where you don’t have a primary and only have a
few surviving members, MongoDB allows us to force the reconfiguration from any
alive member.&lt;/p&gt;
&lt;p&gt;Let’s connect to one of the secondary nodes in the replica cluster and perform
the failover:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;kubectl exec -it psmdb-client-7b9f978649-pjb2k -- mongo &amp;#39;mongodb://clusterAdmin:&amp;lt;pass&amp;gt;@replica-cluster-rs0-0.replica.svc.cluster.local/admin?ssl=false&amp;#39;
...
rs0:SECONDARY&amp;gt; cfg = rs.config()
rs0:SECONDARY&amp;gt; cfg.members = [cfg.members[3], cfg.members[4], cfg.members[5]]
rs0:SECONDARY&amp;gt; rs.reconfig(cfg, {force: true})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note that the indexes of surviving members may differ in your environment. You
should check rs.status() and rs.config() outputs first. The main idea is to
repopulate config members with only surviving members.&lt;/p&gt;
&lt;p&gt;After the reconfiguration, the replica set will have just three members and two
of them will have votes and a majority. So, they’ll be able to select a new
primary. After performing the same process on the cfg replica set, we will be
able to read and write through mongos again:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;% ./psmdb-tester
2021/09/03 18:41:48 Successfully connected and pinged 34.141.3.189:27017
2021/09/03 18:41:49 read succeed
2021/09/03 18:41:50 read succeed
2021/09/03 18:41:51 read succeed
2021/09/03 18:41:52 read succeed
2021/09/03 18:41:53 read succeed
2021/09/03 18:41:54 read succeed
2021/09/03 18:41:55 read succeed
2021/09/03 18:41:56 read succeed
2021/09/03 18:41:57 read succeed
2021/09/03 18:41:58 read succeed
2021/09/03 18:41:58 write succeed
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Once the replica cluster has become the primary, you should reconfigure all
clients that connect to the old main cluster and point them to the DR site.&lt;/p&gt;
</description>
      <category>mongodb</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Cluster Statuses in Percona Kubernetes Operators</title>
      <link>https://ege.dev/entries/2021/07/cluster-statuses-in-percona-kubernetes-operators/</link>
      <pubDate>Wed, 21 Jul 2021 15:10:57 +0300</pubDate>
      <guid isPermaLink="false">https://ege.dev/entries/2021/07/cluster-statuses-in-percona-kubernetes-operators/</guid>
      <description>&lt;p&gt;In Kubernetes, all resources have a status field separated from their spec. The
status field is an interface both for humans or applications to read the
perceived state of the resource.&lt;/p&gt;
&lt;p&gt;When you deploy our Percona Kubernetes Operators –  Percona Operator for
MongoDB or Percona Operator for MySQL – in your Kubernetes cluster, you’re
creating a custom resource (CR for short) and it has its own status, too. Since
Kubernetes operators mimic the human operator and aim to have the required
expertise to run software in a Kubernetes cluster; the status of the custom
resources should be smart.&lt;/p&gt;
&lt;p&gt;You can get cluster status with the commands below, or via (Kubernetes API) for
Percona Operator for MySQL:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;% kubectl get pxc
NAME            ENDPOINT                                   STATUS   PXC   PROXYSQL   HAPROXY   AGE
lisette-18537   lisette-18537-haproxy.subjectivism-22940   ready    3                3         87m

% kubectl get pxc &amp;lt;cluster-name&amp;gt; -o jsonpath=&amp;#39;{.status}&amp;#39;
{
  &amp;#34;backup&amp;#34;: {
    &amp;#34;version&amp;#34;: &amp;#34;8.0.23&amp;#34;
  },
  &amp;#34;conditions&amp;#34;: [
    {
      &amp;#34;lastTransitionTime&amp;#34;: &amp;#34;2021-07-12T13:13:46Z&amp;#34;,
      &amp;#34;status&amp;#34;: &amp;#34;True&amp;#34;,
      &amp;#34;type&amp;#34;: &amp;#34;initializing&amp;#34;
    }
  ],
  &amp;#34;haproxy&amp;#34;: {
    &amp;#34;labelSelectorPath&amp;#34;: &amp;#34;...&amp;#34;,
    &amp;#34;ready&amp;#34;: 3,
    &amp;#34;size&amp;#34;: 3,
    &amp;#34;status&amp;#34;: &amp;#34;ready&amp;#34;
  },
  &amp;#34;host&amp;#34;: &amp;#34;lisette-18537-haproxy.subjectivism-22940&amp;#34;,
  &amp;#34;logcollector&amp;#34;: {
    &amp;#34;version&amp;#34;: &amp;#34;1.8.0&amp;#34;
  },
  &amp;#34;observedGeneration&amp;#34;: 2,
  &amp;#34;pmm&amp;#34;: {
    &amp;#34;version&amp;#34;: &amp;#34;2.12.0&amp;#34;
  },
  &amp;#34;proxysql&amp;#34;: {},
  &amp;#34;pxc&amp;#34;: {
    &amp;#34;image&amp;#34;: &amp;#34;percona/percona-xtradb-cluster:8.0.22-13.1&amp;#34;,
    &amp;#34;labelSelectorPath&amp;#34;: &amp;#34;...&amp;#34;,
    &amp;#34;ready&amp;#34;: 2,
    &amp;#34;size&amp;#34;: 3,
    &amp;#34;status&amp;#34;: &amp;#34;initializing&amp;#34;,
    &amp;#34;version&amp;#34;: &amp;#34;8.0.22-13.1&amp;#34;
  },
  &amp;#34;ready&amp;#34;: 5,
  &amp;#34;size&amp;#34;: 6,
  &amp;#34;state&amp;#34;: &amp;#34;initializing&amp;#34;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And for Percona Operator for MongoDB:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;% kubectl get psmdb
NAME             ENDPOINT                                                     STATUS   AGE
cynodont-26997   cynodont-26997-mongos.subjectivism-22940.svc.cluster.local   ready    85m


% kubectl get psmdb &amp;lt;cluster-name&amp;gt; -o jsonpath=&amp;#39;{.status}&amp;#39;
{
  &amp;#34;conditions&amp;#34;: [
    {
      &amp;#34;lastTransitionTime&amp;#34;: &amp;#34;2021-07-12T13:13:39Z&amp;#34;,
      &amp;#34;status&amp;#34;: &amp;#34;True&amp;#34;,
      &amp;#34;type&amp;#34;: &amp;#34;initializing&amp;#34;
    }
  ],
  &amp;#34;host&amp;#34;: &amp;#34;cynodont-26997-mongos.subjectivism-22940.svc.cluster.local&amp;#34;,
  &amp;#34;mongoImage&amp;#34;: &amp;#34;percona/percona-server-mongodb:4.4.6-8&amp;#34;,
  &amp;#34;mongoVersion&amp;#34;: &amp;#34;4.4.6-8&amp;#34;,
  &amp;#34;mongos&amp;#34;: {
    &amp;#34;ready&amp;#34;: 1,
    &amp;#34;size&amp;#34;: 3,
    &amp;#34;status&amp;#34;: &amp;#34;initializing&amp;#34;
  },
  &amp;#34;observedGeneration&amp;#34;: 2,
  &amp;#34;ready&amp;#34;: 3,
  &amp;#34;replsets&amp;#34;: {
    &amp;#34;cfg&amp;#34;: {
      &amp;#34;ready&amp;#34;: 1,
      &amp;#34;size&amp;#34;: 3,
      &amp;#34;status&amp;#34;: &amp;#34;initializing&amp;#34;
    },
    &amp;#34;rs0&amp;#34;: {
      &amp;#34;initialized&amp;#34;: true,
      &amp;#34;ready&amp;#34;: 2,
      &amp;#34;size&amp;#34;: 3,
      &amp;#34;status&amp;#34;: &amp;#34;initializing&amp;#34;
    }
  },
  &amp;#34;size&amp;#34;: 6,
  &amp;#34;state&amp;#34;: &amp;#34;initializing&amp;#34;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As you can see there are several fields in the output: conditions, cluster
size, number of ready cluster members, statuses and versions of different
components, and the “state”. In the following sections, we’ll take a look at
every possible value of the state field.&lt;/p&gt;
&lt;h2 id=&#34;initializing&#34;&gt;Initializing&lt;/h2&gt;
&lt;p&gt;While the cluster is progressing to readiness, CR status is “initializing”. It
includes creating the cluster, scaling it up or down, and updating the CR that
triggers a rolling restart of pods (for instance updating Percona Operator for
MySQL memory limits).&lt;/p&gt;
&lt;p&gt;Percona Operator for MongoDB also reconfigures the replica set config if
necessary (for instance it adds the new pods as members to replset or removes
terminated ones). Replica set in MongoDB is a set of servers that implements
replication and automatic failover. Although they have the same name, it’s
different from the Kubernetes replica set. While this configuration is
happening or if there is an unknown/unpredicted error during it, the status is
also “initializing”.&lt;/p&gt;
&lt;p&gt;Since version 1.7.0, the Percona Operator for MySQL can handle full crash
recovery if necessary. If a pod waits for the recovery, the cluster status is
“initializing”.&lt;/p&gt;
&lt;h2 id=&#34;ready&#34;&gt;Ready&lt;/h2&gt;
&lt;p&gt;The operator keeps track of the status of each component in the cluster.
Percona Operator for MongoDB has the following components:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;mongod StatefulSet&lt;/li&gt;
&lt;li&gt;configsvr StatefulSet if sharding is enabled&lt;/li&gt;
&lt;li&gt;mongos Deployment if sharding is enabled&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Percona Operator for MySQL components:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;PXC StatefulSet&lt;/li&gt;
&lt;li&gt;HAProxy StatefulSet if enabled&lt;/li&gt;
&lt;li&gt;ProxySQL StatefulSet if enabled&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All components need to be in “ready” status for CR to be “ready”. If the number
of ready pods controlled by the stateful set reaches the desired number, the
operator marks the component as ready. The readiness of the pods is tracked by
Kubernetes using readiness probes for each container in the pod. For example,
for a Percona XtraDB Cluster container to be ready “wsrep_cluster_status” needs
to be “Primary” and “wsrep_local_state” should be “Synced” or “Donor”. For a
Percona Server for MongoDB container to be ready, accepting TCP connections on
27017 is enough.&lt;/p&gt;
&lt;p&gt;But ready as the CR status means more than that. CR “ready” means the cluster
(Percona Server for MongoDB or Percona XtraDB Cluster) is up and running and
ready to receive traffic. So, even if all components are ready, the cluster
status can be “initializing”. In the Percona Operator for MongoDB, the replica
set needs to be initialized and its config up-to-date. Also, with the 1.9.0
release of both operators, the load balancer needs to be ready if the cluster
is exposed with &lt;code&gt;exposeType: LoadBalancer&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;stopping&#34;&gt;Stopping&lt;/h2&gt;
&lt;p&gt;Version 1.9.0 introduced two new statuses:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Stopping&lt;/li&gt;
&lt;li&gt;Paused&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Stopping means the cluster is paused or deleted and its pods are terminating right now.&lt;/p&gt;
&lt;p&gt;If you run &lt;code&gt;kubectl delete psmdb &amp;lt;cluster-name&amp;gt;&lt;/code&gt; or `kubectl delete pxc
&lt;cluster-name&gt;`` the resource can be deleted quickly without a chance to see
“stopping” status. If you had finalizers (for example
“delete-pxc-pods-in-order” in Percona Operator for MySQL) deletion will be
blocked until the finalizer list is exhausted and you can observe “stopping”
status.&lt;/p&gt;
&lt;h2 id=&#34;paused&#34;&gt;Paused&lt;/h2&gt;
&lt;p&gt;Once the cluster is paused and all pods are terminated, the CR status becomes “paused”.&lt;/p&gt;
&lt;p&gt;To pause the cluster: &lt;code&gt;kubectl patch &amp;lt;psmdb|pxc&amp;gt; &amp;lt;cluster-name&amp;gt; --type=merge -p &#39;{&amp;quot;spec&amp;quot;: {&amp;quot;pause&amp;quot;: true}}&#39;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Keep in mind, when the cluster is paused and exposeType is LoadBalancer – Load
balancers are still there and you continue to pay for them.&lt;/p&gt;
&lt;h2 id=&#34;error&#34;&gt;Error&lt;/h2&gt;
&lt;p&gt;Before 1.9.0, “error” status could mean two different things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;An error occurred in the operator during the reconciliation of the CR&lt;/li&gt;
&lt;li&gt;One or more pods in a component are not schedulable&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With 1.9.0, the “error” status means only the operator errors. If there is an
unschedulable pod, the cluster’s status will be initializing. If the cluster is
stuck in initializing for too long, it’s better to check the operator logs to
investigate.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;% kubectl logs &amp;lt;operator-pod-name&amp;gt;
...
{&amp;#34;level&amp;#34;:&amp;#34;info&amp;#34;,&amp;#34;ts&amp;#34;:1626095618.9982307,&amp;#34;logger&amp;#34;:&amp;#34;controller_psmdb&amp;#34;,&amp;#34;msg&amp;#34;:&amp;#34;Created a new mongo key&amp;#34;,&amp;#34;Request.Namespace&amp;#34;:&amp;#34;subjectivism-22940&amp;#34;,&amp;#34;Request.Name&amp;#34;:&amp;#34;cynodont-26997&amp;#34;,&amp;#34;KeyName&amp;#34;:&amp;#34;cynodont-26997-mongodb-keyfile&amp;#34;}
{&amp;#34;level&amp;#34;:&amp;#34;info&amp;#34;,&amp;#34;ts&amp;#34;:1626095619.0032709,&amp;#34;logger&amp;#34;:&amp;#34;controller_psmdb&amp;#34;,&amp;#34;msg&amp;#34;:&amp;#34;Created a new mongo key&amp;#34;,&amp;#34;Request.Namespace&amp;#34;:&amp;#34;subjectivism-22940&amp;#34;,&amp;#34;Request.Name&amp;#34;:&amp;#34;cynodont-26997&amp;#34;,&amp;#34;KeyName&amp;#34;:&amp;#34;cynodont-26997-mongodb-encryption-key&amp;#34;}
{&amp;#34;level&amp;#34;:&amp;#34;info&amp;#34;,&amp;#34;ts&amp;#34;:1626095687.3783236,&amp;#34;logger&amp;#34;:&amp;#34;controller_psmdb&amp;#34;,&amp;#34;msg&amp;#34;:&amp;#34;initiating replset&amp;#34;,&amp;#34;replset&amp;#34;:&amp;#34;rs0&amp;#34;,&amp;#34;pod&amp;#34;:&amp;#34;cynodont-26997-rs0-1&amp;#34;}
{&amp;#34;level&amp;#34;:&amp;#34;info&amp;#34;,&amp;#34;ts&amp;#34;:1626095694.020591,&amp;#34;logger&amp;#34;:&amp;#34;controller_psmdb&amp;#34;,&amp;#34;msg&amp;#34;:&amp;#34;replset was initialized&amp;#34;,&amp;#34;replset&amp;#34;:&amp;#34;rs0&amp;#34;,&amp;#34;pod&amp;#34;:&amp;#34;cynodont-26997-rs0-1&amp;#34;}
{&amp;#34;level&amp;#34;:&amp;#34;error&amp;#34;,&amp;#34;ts&amp;#34;:1626095694.622869,&amp;#34;logger&amp;#34;:&amp;#34;controller_psmdb&amp;#34;,&amp;#34;msg&amp;#34;:&amp;#34;failed to reconcile cluster&amp;#34;,&amp;#34;Request.Namespace&amp;#34;:&amp;#34;subjectivism-22940&amp;#34;,&amp;#34;Request.Name&amp;#34;:&amp;#34;cynodont-26997&amp;#34;,&amp;#34;replset&amp;#34;:&amp;#34;rs0&amp;#34;,&amp;#34;error&amp;#34;:&amp;#34;undefined state of the replset member cynodont-26997-rs0-0.cynodont-26997-rs0.subjectivism-22940.svc.cluster.local:27017: 6&amp;#34;,&amp;#34;errorVerbose&amp;#34;:&amp;#34;undefined state of the replset member cynodont-26997-rs0-0.cynodont-26997-rs0.subjectivism-22940.svc.cluster.local:27017: 6\ngithub.com/percona/percona-server-mongodb-operator/pkg/controller/perconaservermongodb.(*ReconcilePerconaServerMongoDB).reconcileCluster\n\t/go/src/github.com/percona/percona-server-mongodb-operator/pkg/controller/perconaservermongodb/mgo.go:210\ngithub.com/percona/percona-server-mongodb-operator/pkg/controller/perconaservermongodb.(*ReconcilePerconaServerMongoDB).Reconcile\n\t/go/src/github.com/percona/percona-server-mongodb-operator/pkg/controller/perconaservermongodb/psmdb_controller.go:449\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:256\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:232\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).worker\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:211\nk8s.io/apimachinery/pkg/util/wait.JitterUntil.func1\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:152\nk8s.io/apimachinery/pkg/util/wait.JitterUntil\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:153\nk8s.io/apimachinery/pkg/util/wait.Until\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:88\nruntime.goexit\n\t/usr/local/go/src/runtime/asm_amd64.s:1371&amp;#34;,&amp;#34;stacktrace&amp;#34;:&amp;#34;github.com/go-logr/zapr.(*zapLogger).Error\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/github.com/go-logr/zapr/zapr.go:128\ngithub.com/percona/percona-server-mongodb-operator/pkg/controller/perconaservermongodb.(*ReconcilePerconaServerMongoDB).Reconcile\n\t/go/src/github.com/percona/percona-server-mongodb-operator/pkg/controller/perconaservermongodb/psmdb_controller.go:451\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:256\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:232\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).worker\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:211\nk8s.io/apimachinery/pkg/util/wait.JitterUntil.func1\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:152\nk8s.io/apimachinery/pkg/util/wait.JitterUntil\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:153\nk8s.io/apimachinery/pkg/util/wait.Until\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:88&amp;#34;}
% kubectl logs &amp;lt;operator-pod-name&amp;gt;
 
...
{&amp;#34;level&amp;#34;:&amp;#34;info&amp;#34;,&amp;#34;ts&amp;#34;:1626095618.9982307,&amp;#34;logger&amp;#34;:&amp;#34;controller_psmdb&amp;#34;,&amp;#34;msg&amp;#34;:&amp;#34;Created a new mongo key&amp;#34;,&amp;#34;Request.Namespace&amp;#34;:&amp;#34;subjectivism-22940&amp;#34;,&amp;#34;Request.Name&amp;#34;:&amp;#34;cynodont-26997&amp;#34;,&amp;#34;KeyName&amp;#34;:&amp;#34;cynodont-26997-mongodb-keyfile&amp;#34;}
{&amp;#34;level&amp;#34;:&amp;#34;info&amp;#34;,&amp;#34;ts&amp;#34;:1626095619.0032709,&amp;#34;logger&amp;#34;:&amp;#34;controller_psmdb&amp;#34;,&amp;#34;msg&amp;#34;:&amp;#34;Created a new mongo key&amp;#34;,&amp;#34;Request.Namespace&amp;#34;:&amp;#34;subjectivism-22940&amp;#34;,&amp;#34;Request.Name&amp;#34;:&amp;#34;cynodont-26997&amp;#34;,&amp;#34;KeyName&amp;#34;:&amp;#34;cynodont-26997-mongodb-encryption-key&amp;#34;}
{&amp;#34;level&amp;#34;:&amp;#34;info&amp;#34;,&amp;#34;ts&amp;#34;:1626095687.3783236,&amp;#34;logger&amp;#34;:&amp;#34;controller_psmdb&amp;#34;,&amp;#34;msg&amp;#34;:&amp;#34;initiating replset&amp;#34;,&amp;#34;replset&amp;#34;:&amp;#34;rs0&amp;#34;,&amp;#34;pod&amp;#34;:&amp;#34;cynodont-26997-rs0-1&amp;#34;}
{&amp;#34;level&amp;#34;:&amp;#34;info&amp;#34;,&amp;#34;ts&amp;#34;:1626095694.020591,&amp;#34;logger&amp;#34;:&amp;#34;controller_psmdb&amp;#34;,&amp;#34;msg&amp;#34;:&amp;#34;replset was initialized&amp;#34;,&amp;#34;replset&amp;#34;:&amp;#34;rs0&amp;#34;,&amp;#34;pod&amp;#34;:&amp;#34;cynodont-26997-rs0-1&amp;#34;}
{&amp;#34;level&amp;#34;:&amp;#34;error&amp;#34;,&amp;#34;ts&amp;#34;:1626095694.622869,&amp;#34;logger&amp;#34;:&amp;#34;controller_psmdb&amp;#34;,&amp;#34;msg&amp;#34;:&amp;#34;failed to reconcile cluster&amp;#34;,&amp;#34;Request.Namespace&amp;#34;:&amp;#34;subjectivism-22940&amp;#34;,&amp;#34;Request.Name&amp;#34;:&amp;#34;cynodont-26997&amp;#34;,&amp;#34;replset&amp;#34;:&amp;#34;rs0&amp;#34;,&amp;#34;error&amp;#34;:&amp;#34;undefined state of the replset member cynodont-26997-rs0-0.cynodont-26997-rs0.subjectivism-22940.svc.cluster.local:27017: 6&amp;#34;,&amp;#34;errorVerbose&amp;#34;:&amp;#34;undefined state of the replset member cynodont-26997-rs0-0.cynodont-26997-rs0.subjectivism-22940.svc.cluster.local:27017: 6\ngithub.com/percona/percona-server-mongodb-operator/pkg/controller/perconaservermongodb.(*ReconcilePerconaServerMongoDB).reconcileCluster\n\t/go/src/github.com/percona/percona-server-mongodb-operator/pkg/controller/perconaservermongodb/mgo.go:210\ngithub.com/percona/percona-server-mongodb-operator/pkg/controller/perconaservermongodb.(*ReconcilePerconaServerMongoDB).Reconcile\n\t/go/src/github.com/percona/percona-server-mongodb-operator/pkg/controller/perconaservermongodb/psmdb_controller.go:449\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:256\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:232\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).worker\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:211\nk8s.io/apimachinery/pkg/util/wait.JitterUntil.func1\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:152\nk8s.io/apimachinery/pkg/util/wait.JitterUntil\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:153\nk8s.io/apimachinery/pkg/util/wait.Until\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:88\nruntime.goexit\n\t/usr/local/go/src/runtime/asm_amd64.s:1371&amp;#34;,&amp;#34;stacktrace&amp;#34;:&amp;#34;github.com/go-logr/zapr.(*zapLogger).Error\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/github.com/go-logr/zapr/zapr.go:128\ngithub.com/percona/percona-server-mongodb-operator/pkg/controller/perconaservermongodb.(*ReconcilePerconaServerMongoDB).Reconcile\n\t/go/src/github.com/percona/percona-server-mongodb-operator/pkg/controller/perconaservermongodb/psmdb_controller.go:451\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).reconcileHandler\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:256\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).processNextWorkItem\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:232\nsigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller).worker\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go:211\nk8s.io/apimachinery/pkg/util/wait.JitterUntil.func1\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:152\nk8s.io/apimachinery/pkg/util/wait.JitterUntil\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:153\nk8s.io/apimachinery/pkg/util/wait.Until\n\t/go/src/github.com/percona/percona-server-mongodb-operator/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:88&amp;#34;}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can try new statuses in version 1.9.0 of both Percona Operator for MongoDB
and Percona Operator for MySQL. Percona Operator for MongoDB was released in
June and Percona Operator for MySQL is on the way.&lt;/p&gt;
</description>
      <category>kubernetes</category>
      <category>mongodb</category>
      <category>mysql</category>
    </item>
  </channel>
</rss>
