Exemplo n.º 1
0
  def test_wait_for_statefulset(self):
    api_client = mock.MagicMock(spec=k8s_client.ApiClient)

    response = k8s_client.V1beta1StatefulSet()
    response.status = k8s_client.V1beta1StatefulSetStatus(
      ready_replicas=1, replicas=1)
    api_client.call_api.return_value = response
    result = util.wait_for_statefulset(api_client, "some-namespace", "some-set")
    self.assertIsNotNone(result)
Exemplo n.º 2
0
    def set_image_for_stateful_set(self, sts_name, container_name,
                                   service_name, image):
        stateful_set_spec_template_spec_containers = [
            client.V1Container(name=container_name, image=image)
        ]

        stateful_set_spec_template_spec = client.V1PodSpec(
            containers=stateful_set_spec_template_spec_containers)

        stateful_set_spec_template = client.V1PodTemplateSpec(
            spec=stateful_set_spec_template_spec)

        stateful_set_spec = client.V1beta1StatefulSetSpec(
            template=stateful_set_spec_template, service_name=service_name)

        stateful_set = client.V1beta1StatefulSet(spec=stateful_set_spec)

        self.appsv1betaapi.patch_namespaced_stateful_set(
            name=sts_name, namespace=self.namespace, body=stateful_set)
Exemplo n.º 3
0
    def createStatefulSet(cls, cluster_object: V1MongoClusterConfiguration) -> client.V1beta1StatefulSet:
        """
        Creates a the stateful set configuration for the given cluster.
        :param cluster_object: The cluster object from the YAML file.
        :return: The stateful set object.
        """

        # Parse cluster data object.
        name = cluster_object.metadata.name
        namespace = cluster_object.metadata.namespace
        replicas = cluster_object.spec.mongodb.replicas
        storage_mount_path = cluster_object.spec.mongodb.host_path or cls.DEFAULT_STORAGE_MOUNT_PATH
        host_path = cluster_object.spec.mongodb.host_path
        cpu_limit = cluster_object.spec.mongodb.cpu_limit or cls.DEFAULT_CPU_LIMIT
        memory_limit = cluster_object.spec.mongodb.memory_limit or cls.DEFAULT_MEMORY_LIMIT
        run_as_user = cluster_object.spec.mongodb.run_as_user or cls.DEFAULT_RUN_AS_USER
        service_account = cluster_object.spec.mongodb.service_account or cls.DEFAULT_SERVICE_ACCOUNT
        wired_tiger_cache_size = cluster_object.spec.mongodb.wired_tiger_cache_size or cls.DEFAULT_CACHE_SIZE
        secret_name = cls.ADMIN_SECRET_NAME_FORMAT.format(name)

        # create container
        mongo_container = client.V1Container(
            name=name,
            env=[client.V1EnvVar(
                name="POD_IP",
                value_from=client.V1EnvVarSource(
                    field_ref = client.V1ObjectFieldSelector(
                        api_version = "v1",
                        field_path = "status.podIP"
                    )
                )
            ),
            client.V1EnvVar(
                name="MONGODB_PASSWORD",
                value_from=client.V1EnvVarSource(
                    secret_key_ref=client.V1SecretKeySelector(
                        key="database-password",
                        name=secret_name
                    )
                )
            ),
            client.V1EnvVar(
                name="MONGODB_USER",
                value_from=client.V1EnvVarSource(
                    secret_key_ref=client.V1SecretKeySelector(
                        key="database-user",
                        name=secret_name
                    )
                )
            ),
            client.V1EnvVar(
                name="MONGODB_DATABASE",
                value_from=client.V1EnvVarSource(
                    secret_key_ref=client.V1SecretKeySelector(
                        key="database-name",
                        name=secret_name
                    )
                )
            ),
            client.V1EnvVar(
                name="MONGODB_ADMIN_PASSWORD",
                value_from=client.V1EnvVarSource(
                    secret_key_ref=client.V1SecretKeySelector(
                        key="database-admin-password",
                        name=secret_name
                    )
                )
            ),
            client.V1EnvVar(
              name="WIREDTIGER_CACHE_SIZE",
              value=wired_tiger_cache_size
            ),
            client.V1EnvVar(
                name="MONGODB_REPLICA_NAME",
                value=name
            ),
            client.V1EnvVar(
                name="MONGODB_SERVICE_NAME",
                value="svc-" + name + "-internal"
            ),
            client.V1EnvVar(
                name="MONGODB_KEYFILE_VALUE",
                value="supersecretkeyfile123"
            )],
            liveness_probe=client.V1Probe(failure_threshold=3,
                                          initial_delay_seconds=30,
                                          period_seconds=30,
                                          success_threshold=1,
                                          tcp_socket=client.V1TCPSocketAction(port=cls.MONGO_PORT),
                                          timeout_seconds=1
            ),
            command=cls.MONGO_COMMAND.split(),
            image=cls.MONGO_IMAGE,
            image_pull_policy="Always",
            ports=[client.V1ContainerPort(
                name="mongodb",
                container_port=cls.MONGO_PORT,
                protocol="TCP"
            )],
            readiness_probe=client.V1Probe(_exec=client.V1ExecAction(command=["/bin/sh", "-i", "-c", "mongo 127.0.0.1:27017/$MONGODB_DATABASE -u $MONGODB_USER -p $MONGODB_PASSWORD --eval=\"quit()\""]),
                                           failure_threshold=3,
                                           initial_delay_seconds=10,
                                           period_seconds=10,
                                           success_threshold=1,
                                           timeout_seconds=1
                                           ),
            security_context=client.V1SecurityContext(
                run_as_user=int(run_as_user),
                se_linux_options=client.V1SELinuxOptions(
                    level="s0",
                    type="spc_t"
                )
            ),
            termination_message_path="/dev/termination-log",
            volume_mounts=[client.V1VolumeMount(
                name="mongo-data",
                read_only=False,
                mount_path=storage_mount_path
            )],
            resources=client.V1ResourceRequirements(
                limits={"cpu": cpu_limit, "memory": memory_limit},
                requests={"cpu": cpu_limit, "memory": memory_limit}
            )
        )

        #create affinity rules
        affinity = client.V1Affinity(
            pod_anti_affinity=client.V1PodAntiAffinity(
                required_during_scheduling_ignored_during_execution=[
                    client.V1PodAffinityTerm(label_selector=client.V1LabelSelector(
                        match_expressions=[client.V1LabelSelectorRequirement(
                            key="app",
                            operator="In",
                            values=[name]
                        )]
                    ),
                     topology_key="kubernetes.io/hostname")
                ]
            )
        )

        volumes = [client.V1Volume(
            name="mongo-data",
            host_path=client.V1HostPathVolumeSource(path=host_path)
        )]

        # Create stateful set.
        return client.V1beta1StatefulSet(
            metadata = client.V1ObjectMeta(annotations={"service.alpha.kubernetes.io/tolerate-unready-endpoints": "true"},
                                           name=name,
                                           namespace=namespace,
                                           labels=cls.createDefaultLabels(name)),
            spec = client.V1beta1StatefulSetSpec(
                replicas = replicas,
                service_name = "svc-" + name + "-internal",
                template = client.V1PodTemplateSpec(
                    metadata = client.V1ObjectMeta(labels=cls.createDefaultLabels(name)),
                    spec = client.V1PodSpec(affinity = affinity,
                                            containers=[mongo_container],
                                            node_selector={"compute":"mongodb"},
                                            service_account=service_account,
                                            #restart_policy="Never",
                                            volumes=volumes
                    )
                ),
            ),
        )
Exemplo n.º 4
0
    def generate_stateful_set(self):

        volume_claim_spec = client.V1PersistentVolumeClaimSpec(**self.volume_claim_spec)
        if not volume_claim_spec.access_modes:
            volume_claim_spec.access_modes = ["ReadWriteOnce"]
        if not volume_claim_spec.resources:
            volume_claim_spec.resources = client.V1ResourceRequirements(
                requests={"storage": "20Gi"}
            )

        stateful_set = client.V1beta1StatefulSet(
            metadata=self.metadata,
            spec=client.V1beta1StatefulSetSpec(
                # we can't update service name or pod management policy
                service_name=self.full_name + "-headless",
                pod_management_policy="Parallel",
                # we can't update volume claim templates
                volume_claim_templates=[client.V1PersistentVolumeClaim(
                    metadata=client.V1ObjectMeta(
                        name="image-store",
                    ),
                    spec=volume_claim_spec,
                )]
            )
        )

        stateful_set.spec.replicas = 2
        pod_labels = {'component': 'registry'}
        pod_labels.update(self.labels)
        volumes = []
        if self.ca_certificate_bundle:
            volumes = [
                client.V1Volume(
                    name=self.ca_certificate_bundle,
                    config_map=client.V1ConfigMapVolumeSource(
                        name=self.ca_certificate_bundle
                    )
                )
            ]
        volumes.append(
            client.V1Volume(
                name="tls",
                secret=client.V1SecretVolumeSource(
                    secret_name=self.docker_certificate_secret
                ),
            )
        )

        volumes_to_mount = [
            client.V1VolumeMount(
                name="image-store",
                mount_path="/var/lib/registry"
            ),
            client.V1VolumeMount(
                name="tls",
                mount_path="/etc/registry-certs",
                read_only=True
            )
        ]
        if self.ca_certificate_bundle:
            volumes_to_mount.append(
                client.V1VolumeMount(
                    name=self.ca_certificate_bundle,
                    mount_path="/etc/ssl/certs",
                    read_only=True
                )
            )

        env = [client.V1EnvVar(name="REGISTRY_PROXY_REMOTEURL",
                               value="https://" + self.upstreamUrl),
               client.V1EnvVar(name="REGISTRY_HTTP_ADDR",
                               value=":5000"),
               client.V1EnvVar(name="REGISTRY_HTTP_DEBUG_ADDR",
                               value="localhost:6000"),
               client.V1EnvVar(name="REGISTRY_HTTP_TLS_CERTIFICATE",
                               value="/etc/registry-certs/tls.crt"),
               client.V1EnvVar(name="REGISTRY_HTTP_TLS_KEY",
                               value="/etc/registry-certs/tls.key"),
               client.V1EnvVar(name="REGISTRY_LOG_ACCESSLOG_DISABLED",
                               value="true"),
               client.V1EnvVar(name="REGISTRY_LOG_FORMATTER",
                               value="logstash"),
               client.V1EnvVar(name="REGISTRY_STORAGE_DELETE_ENABLED",
                               value="true"),
               client.V1EnvVar(name="REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY",
                               value="/var/lib/registry")
               ]
        env = self.handle_proxy_credentials(env)

        stateful_set.spec.template = client.V1PodTemplateSpec(
                    metadata=client.V1ObjectMeta(
                        labels=pod_labels
                    ),
                    spec=client.V1PodSpec(
                        init_containers=[
                            client.V1Container(
                                name="validate-state-file",
                                image="python:3.6-alpine",
                                env=[
                                    client.V1EnvVar(
                                        name="STATE_FILE",
                                        value="/var/lib/registry/scheduler-state.json"
                                    ),
                                    client.V1EnvVar(
                                        name="LOWER_LIMIT",
                                        value="1024"
                                    ),
                                ],
                                volume_mounts=[
                                    client.V1VolumeMount(
                                        name="image-store",
                                        mount_path="/var/lib/registry"
                                    )
                                ],
                                command=[
                                    "sh",
                                    "-e",
                                    "-c",
                                    "touch $STATE_FILE; if [[ $(stat -c \"%s\" $STATE_FILE) -lt $LOWER_LIMIT ]]; then rm -f $STATE_FILE; else cat $STATE_FILE | python -m json.tool > /dev/null 2>&1 || rm -f $STATE_FILE; fi"  # noqa
                                ]
                            )
                        ],
                        containers=[
                            client.V1Container(
                                name="registry",
                                image="registry:2.6.0",
                                env=env,
                                readiness_probe=client.V1Probe(
                                    http_get=client.V1HTTPGetAction(
                                        path="/",
                                        port=5000,
                                        scheme="HTTPS"
                                    ),
                                    initial_delay_seconds=3,
                                    period_seconds=3
                                ),
                                ports=[client.V1ContainerPort(
                                    container_port=5000,
                                    name="https"
                                )],
                                resources=client.V1ResourceRequirements(
                                    requests={"cpu": "0.1",
                                              "memory": "500Mi"},
                                    limits={"cpu": "0.5",
                                            "memory": "500Mi"}
                                ),
                                volume_mounts=volumes_to_mount,
                            )
                        ],
                        termination_grace_period_seconds=10,
                        volumes=volumes,
                    )
                )
        stateful_set.spec.update_strategy = client.V1beta1StatefulSetUpdateStrategy(type="RollingUpdate",)
        return stateful_set
Exemplo n.º 5
0
    def createStatefulSet(
        cls, cluster_object: V1MongoClusterConfiguration
    ) -> client.V1beta1StatefulSet:
        """
        Creates a the stateful set configuration for the given cluster.
        :param cluster_object: The cluster object from the YAML file.
        :return: The stateful set object.
        """

        # Parse cluster data object.
        name = cluster_object.metadata.name
        storage_name = cluster_object.spec.mongodb.storage_name or cls.DEFAULT_STORAGE_NAME
        storage_size = cluster_object.spec.mongodb.storage_size or cls.DEFAULT_STORAGE_SIZE
        storage_mount_path = cluster_object.spec.mongodb.storage_data_path or cls.DEFAULT_STORAGE_MOUNT_PATH
        storage_class_name = cluster_object.spec.mongodb.storage_class_name or cls.DEFAULT_STORAGE_CLASS_NAME
        cpu_limit = cluster_object.spec.mongodb.cpu_limit or cls.DEFAULT_CPU_LIMIT
        cpu_request = cluster_object.spec.mongodb.cpu_request or cls.DEFAULT_CPU_REQUEST
        memory_limit = cluster_object.spec.mongodb.memory_limit or cls.DEFAULT_MEMORY_LIMIT
        memory_request = cluster_object.spec.mongodb.memory_request or cls.DEFAULT_MEMORY_REQUEST
        wired_tiger_cache_size = cluster_object.spec.mongodb.wired_tiger_cache_size or cls.DEFAULT_CACHE_SIZE

        # create container
        mongo_container = client.V1Container(
            name=cls.MONGO_NAME,
            env=[
                client.V1EnvVar(
                    name="POD_IP",
                    value_from=client.V1EnvVarSource(
                        field_ref=client.V1ObjectFieldSelector(
                            api_version="v1", field_path="status.podIP")))
            ],
            command=cls.MONGO_COMMAND.format(
                name=name, cache_size=wired_tiger_cache_size).split(),
            image=cls.MONGO_IMAGE,
            ports=[
                client.V1ContainerPort(name=cls.MONGO_NAME,
                                       container_port=cls.MONGO_PORT,
                                       protocol="TCP")
            ],
            volume_mounts=[
                client.V1VolumeMount(name=storage_name,
                                     read_only=False,
                                     mount_path=storage_mount_path)
            ],
            resources=client.V1ResourceRequirements(limits={
                "cpu": cpu_limit,
                "memory": memory_limit
            },
                                                    requests={
                                                        "cpu": cpu_request,
                                                        "memory":
                                                        memory_request
                                                    }))

        # Create stateful set.
        return client.V1beta1StatefulSet(
            metadata=client.V1ObjectMeta(
                name=name,
                namespace=cluster_object.metadata.namespace,
                labels=cls.createDefaultLabels(name)),
            spec=client.V1beta1StatefulSetSpec(
                replicas=cluster_object.spec.mongodb.replicas,
                service_name=name,
                template=client.V1PodTemplateSpec(
                    metadata=client.V1ObjectMeta(
                        labels=cls.createDefaultLabels(name)),
                    spec=client.V1PodSpec(containers=[mongo_container]),
                ),
                volume_claim_templates=[
                    client.V1PersistentVolumeClaim(
                        metadata=client.V1ObjectMeta(name=storage_name),
                        spec=client.V1PersistentVolumeClaimSpec(
                            access_modes=["ReadWriteOnce"],
                            resources=client.V1ResourceRequirements(
                                requests={"storage": storage_size}),
                            storage_class_name=storage_class_name),
                    )
                ],
            ),
        )
Exemplo n.º 6
0
def get_statefulset_object(cluster_object):
    name = cluster_object['metadata']['name']
    namespace = cluster_object['metadata']['namespace']

    try:
        replicas = cluster_object['spec']['mongodb']['replicas']
    except KeyError:
        replicas = 3

    try:
        mongodb_limit_cpu = \
            cluster_object['spec']['mongodb']['mongodb_limit_cpu']
    except KeyError:
        mongodb_limit_cpu = '100m'

    try:
        mongodb_limit_memory = \
            cluster_object['spec']['mongodb']['mongodb_limit_memory']
    except KeyError:
        mongodb_limit_memory = '64Mi'

    statefulset = client.V1beta1StatefulSet()

    # Metadata
    statefulset.metadata = client.V1ObjectMeta(
        name=name, namespace=namespace, labels=get_default_labels(name=name))

    # Spec
    statefulset.spec = client.V1beta1StatefulSetSpec(replicas=replicas,
                                                     service_name=name)

    statefulset.spec.template = client.V1PodTemplateSpec()
    statefulset.spec.template.metadata = client.V1ObjectMeta(
        labels=get_default_labels(name=name))

    statefulset.spec.template.spec = client.V1PodSpec()
    statefulset.spec.template.spec.affinity = client.V1Affinity(
        pod_anti_affinity=client.V1PodAntiAffinity(
            required_during_scheduling_ignored_during_execution=[
                client.V1PodAffinityTerm(
                    topology_key='kubernetes.io/hostname',
                    label_selector=client.V1LabelSelector(match_expressions=[
                        client.V1LabelSelectorRequirement(
                            key='cluster', operator='In', values=[name])
                    ]))
            ]))
    # MongoDB container
    mongodb_port = client.V1ContainerPort(name='mongodb',
                                          container_port=27017,
                                          protocol='TCP')
    mongodb_tls_volumemount = client.V1VolumeMount(
        name='mongo-tls', read_only=True, mount_path='/etc/ssl/mongod')
    mongodb_data_volumemount = client.V1VolumeMount(name='mongo-data',
                                                    read_only=False,
                                                    mount_path='/data/db')
    mongodb_resources = client.V1ResourceRequirements(limits={
        'cpu':
        mongodb_limit_cpu,
        'memory':
        mongodb_limit_memory
    },
                                                      requests={
                                                          'cpu':
                                                          mongodb_limit_cpu,
                                                          'memory':
                                                          mongodb_limit_memory
                                                      })
    mongodb_container = client.V1Container(
        name='mongod',
        command=[
            'mongod', '--auth', '--replSet', name, '--sslMode', 'requireSSL',
            '--clusterAuthMode', 'x509', '--sslPEMKeyFile',
            '/etc/ssl/mongod/mongod.pem', '--sslCAFile',
            '/etc/ssl/mongod/ca.pem'
        ],
        image='mongo:3.4.1',
        ports=[mongodb_port],
        volume_mounts=[mongodb_tls_volumemount, mongodb_data_volumemount],
        resources=mongodb_resources)

    # Metrics container
    metrics_port = client.V1ContainerPort(name='metrics',
                                          container_port=9001,
                                          protocol='TCP')
    metrics_resources = client.V1ResourceRequirements(limits={
        'cpu': '50m',
        'memory': '16Mi'
    },
                                                      requests={
                                                          'cpu': '50m',
                                                          'memory': '16Mi'
                                                      })
    metrics_secret_name = '{}-monitoring-credentials'.format(name)
    metrics_username_env_var = client.V1EnvVar(
        name='MONGODB_MONITORING_USERNAME',
        value_from=client.V1EnvVarSource(
            secret_key_ref=client.V1SecretKeySelector(name=metrics_secret_name,
                                                      key='username')))
    metrics_password_env_var = client.V1EnvVar(
        name='MONGODB_MONITORING_PASSWORD',
        value_from=client.V1EnvVarSource(
            secret_key_ref=client.V1SecretKeySelector(name=metrics_secret_name,
                                                      key='password')))
    metrics_container = client.V1Container(
        name='prometheus-exporter',
        image='quay.io/kubestack/prometheus-mongodb-exporter:latest',
        command=[
            '/bin/sh', '-c',
            '/bin/mongodb_exporter --mongodb.uri mongodb://${MONGODB_MONITORING_USERNAME}:${MONGODB_MONITORING_PASSWORD}@127.0.0.1:27017/admin --mongodb.tls-cert /etc/ssl/mongod/mongod.pem --mongodb.tls-ca /etc/ssl/mongod/ca.pem'
        ],  # flake8: noqa
        ports=[metrics_port],
        resources=metrics_resources,
        volume_mounts=[mongodb_tls_volumemount],
        env=[metrics_username_env_var, metrics_password_env_var])

    statefulset.spec.template.spec.containers = [
        mongodb_container, metrics_container
    ]

    ca_volume = client.V1Volume(name='mongo-ca',
                                secret=client.V1SecretVolumeSource(
                                    secret_name='{}-ca'.format(name),
                                    items=[
                                        client.V1KeyToPath(key='ca.pem',
                                                           path='ca.pem'),
                                        client.V1KeyToPath(key='ca-key.pem',
                                                           path='ca-key.pem')
                                    ]))
    tls_volume = client.V1Volume(name='mongo-tls',
                                 empty_dir=client.V1EmptyDirVolumeSource())
    data_volume = client.V1Volume(name='mongo-data',
                                  empty_dir=client.V1EmptyDirVolumeSource())
    statefulset.spec.template.spec.volumes = [
        ca_volume, tls_volume, data_volume
    ]

    # Init container
    # For now use annotation format for init_container to support K8s >= 1.5
    statefulset.spec.template.metadata.annotations = {
        'pod.beta.kubernetes.io/init-containers':
        '[{"name": "cert-init","image": "quay.io/kubestack/mongodb-init:latest","volumeMounts": [{"readOnly": true,"mountPath": "/etc/ssl/mongod-ca","name": "mongo-ca"}, {"mountPath": "/etc/ssl/mongod","name": "mongo-tls"}],"env": [{"name": "METADATA_NAME","valueFrom": {"fieldRef": {"apiVersion": "v1","fieldPath": "metadata.name"}}}, {"name": "NAMESPACE","valueFrom": {"fieldRef": {"apiVersion": "v1","fieldPath": "metadata.namespace"}}}],"command": ["ansible-playbook","member-cert.yml"],"imagePullPolicy": "Always"}]'
    }  # flake8: noqa

    # tls_init_ca_volumemount = client.V1VolumeMount(
    #     name='mongo-ca',
    #     read_only=True,
    #     mount_path='/etc/ssl/mongod-ca')
    # tls_init_container = client.V1Container(
    #     name="cert-init",
    #     image="quay.io/kubestack/mongodb-init:latest",
    #     volume_mounts=[tls_init_ca_volumemount, mongodb_tls_volumemount],
    #     env=[
    #         client.V1EnvVar(
    #             name='METADATA_NAME',
    #             value_from=client.V1EnvVarSource(
    #                 field_ref=client.V1ObjectFieldSelector(
    #                     api_version='v1',
    #                     field_path='metadata.name'))),
    #         client.V1EnvVar(
    #             name='NAMESPACE',
    #             value_from=client.V1EnvVarSource(
    #                 field_ref=client.V1ObjectFieldSelector(
    #                     api_version='v1',
    #                     field_path='metadata.namespace')))],
    #     command=["ansible-playbook", "member-cert.yml"])
    #
    # statefulset.spec.template.spec.init_containers = [tls_init_container]

    return statefulset
Exemplo n.º 7
0
    def create_stateful_set(self, replicas=3, volumeSize=10, namespace=None):
        """
        Create the StatefulSet for the Mongo cluster within a namespace.
        :param replicas: Number of replicas for the StatefulSet.
        :params volumeSize: The size of the volume to be generated via PVC and attached to pods
                            within the statefulSet.
        :param namespace: Namespace to deploy to.
        :return: N/A
        """
        self._create_mongo_configmap(namespace=namespace)

        stateful_set = client.V1beta1StatefulSet(
            metadata=client.V1ObjectMeta(name='mongo',
                                         namespace=namespace,
                                         labels={"app": "MongoStatefulSet"}),
            status=client.V1beta1StatefulSetStatus(replicas=replicas),
            spec=client.V1beta1StatefulSetSpec(
                volume_claim_templates=[
                    client.V1PersistentVolumeClaim(
                        spec=client.V1PersistentVolumeClaimSpec(
                            access_modes=['ReadWriteOnce'],
                            resources=client.V1ResourceRequirements(
                                requests={
                                    "storage": '{0}Gi'.format(volumeSize)
                                })))
                ],
                replicas=replicas,
                selector=client.V1LabelSelector(
                    match_labels={"app": "MongoStatefulSet"}),
                service_name="mongo-service",
                template=client.V1PodTemplateSpec(
                    metadata=client.V1ObjectMeta(
                        name='mongo-pod',
                        namespace=namespace,
                        labels={"app": "MongoStatefulSet"}),
                    spec=client.V1PodSpec(
                        containers=[
                            client.V1Container(
                                name='mongo-container',
                                image=Config.MONGO_IMAGE,
                                image_pull_policy='Always',
                                ports=[
                                    client.V1ContainerPort(
                                        name='mongo',
                                        container_port=27017,
                                        protocol='TCP')
                                ],
                                volume_mounts=[
                                    client.V1VolumeMount(
                                        name='mongo-config-volume',
                                        mount_path='/etc/mongo')
                                ],
                                command=[
                                    "mongod", "-f", "/etc/mongo/mongod.conf"
                                ])
                        ],
                        volumes=[
                            client.V1Volume(
                                name='mongo-config-volume',
                                config_map=client.V1ConfigMapVolumeSource(
                                    default_mode=0o555,
                                    name='mongo-configmap'))
                        ]))))

        try:
            self.apps_v1_api.create_namespaced_stateful_set(
                namespace=namespace, body=stateful_set)
        except ApiException as E:
            if E.status == 409:
                print('Stateful Set already exists.')
            else:
                raise E
Exemplo n.º 8
0
def get_statefulset_object(cluster_object):
    name = cluster_object['metadata']['name']
    namespace = cluster_object['metadata']['namespace']

    try:
        replicas = cluster_object['spec']['mongodb']['replicas']
    except KeyError:
        replicas = 3

    try:
        mongodb_limit_cpu = \
            cluster_object['spec']['mongodb']['mongodb_limit_cpu']
    except KeyError:
        mongodb_limit_cpu = '100m'

    try:
        mongodb_limit_memory = \
            cluster_object['spec']['mongodb']['mongodb_limit_memory']
    except KeyError:
        mongodb_limit_memory = '64Mi'

    try:
        hard_pod_anti_affinity = \
            cluster_object['spec']['mongodb']['hard_pod_anti_affinity']
    except KeyError:
        hard_pod_anti_affinity = True

    statefulset = client.V1beta1StatefulSet()

    # Metadata
    statefulset.metadata = client.V1ObjectMeta(
        name=name, namespace=namespace, labels=get_default_labels(name=name))

    # Spec
    statefulset.spec = client.V1beta1StatefulSetSpec(
        replicas=replicas,
        service_name=name,
        template=client.V1PodTemplateSpec())

    statefulset.spec.template.metadata = client.V1ObjectMeta(
        labels=get_default_labels(name=name))

    statefulset.spec.template.spec = client.V1PodSpec(containers=[])

    pod_affinity_term = client.V1PodAffinityTerm(
        topology_key='kubernetes.io/hostname',
        label_selector=client.V1LabelSelector(match_expressions=[
            client.V1LabelSelectorRequirement(
                key='cluster', operator='In', values=[name])
        ]))

    pod_anti_affinity = client.V1PodAntiAffinity(
        required_during_scheduling_ignored_during_execution=[
            pod_affinity_term
        ])

    if not hard_pod_anti_affinity:
        pod_anti_affinity = client.V1PodAntiAffinity(
            preferred_during_scheduling_ignored_during_execution=[
                client.V1WeightedPodAffinityTerm(
                    weight=100, pod_affinity_term=pod_affinity_term)
            ])

    statefulset.spec.template.spec.affinity = client.V1Affinity(
        pod_anti_affinity=pod_anti_affinity)

    # MongoDB container
    mongodb_port = client.V1ContainerPort(name='mongodb',
                                          container_port=27017,
                                          protocol='TCP')
    mongodb_tls_volumemount = client.V1VolumeMount(
        name='mongo-tls', read_only=True, mount_path='/etc/ssl/mongod')
    mongodb_data_volumemount = client.V1VolumeMount(name='mongo-data',
                                                    read_only=False,
                                                    mount_path='/data/db')
    mongodb_resources = client.V1ResourceRequirements(limits={
        'cpu':
        mongodb_limit_cpu,
        'memory':
        mongodb_limit_memory
    },
                                                      requests={
                                                          'cpu':
                                                          mongodb_limit_cpu,
                                                          'memory':
                                                          mongodb_limit_memory
                                                      })
    mongodb_container = client.V1Container(
        name='mongod',
        env=[
            client.V1EnvVar(
                name='POD_IP',
                value_from=client.V1EnvVarSource(
                    field_ref=client.V1ObjectFieldSelector(
                        api_version='v1', field_path='status.podIP')))
        ],
        command=[
            'mongod', '--auth', '--replSet', name, '--sslMode', 'requireSSL',
            '--clusterAuthMode', 'x509', '--sslPEMKeyFile',
            '/etc/ssl/mongod/mongod.pem', '--sslCAFile',
            '/etc/ssl/mongod/ca.pem', '--bind_ip', '127.0.0.1,$(POD_IP)'
        ],
        image='mongo:3.6.4',
        ports=[mongodb_port],
        volume_mounts=[mongodb_tls_volumemount, mongodb_data_volumemount],
        resources=mongodb_resources)

    # Metrics container
    metrics_port = client.V1ContainerPort(name='metrics',
                                          container_port=9001,
                                          protocol='TCP')
    metrics_resources = client.V1ResourceRequirements(limits={
        'cpu': '50m',
        'memory': '16Mi'
    },
                                                      requests={
                                                          'cpu': '50m',
                                                          'memory': '16Mi'
                                                      })
    metrics_secret_name = '{}-monitoring-credentials'.format(name)
    metrics_username_env_var = client.V1EnvVar(
        name='MONGODB_MONITORING_USERNAME',
        value_from=client.V1EnvVarSource(
            secret_key_ref=client.V1SecretKeySelector(name=metrics_secret_name,
                                                      key='username')))
    metrics_password_env_var = client.V1EnvVar(
        name='MONGODB_MONITORING_PASSWORD',
        value_from=client.V1EnvVarSource(
            secret_key_ref=client.V1SecretKeySelector(name=metrics_secret_name,
                                                      key='password')))
    metrics_container = client.V1Container(
        name='prometheus-exporter',
        image='quay.io/kubestack/prometheus-mongodb-exporter:latest',
        command=[
            '/bin/sh', '-c',
            '/bin/mongodb_exporter --mongodb.uri mongodb://${MONGODB_MONITORING_USERNAME}:${MONGODB_MONITORING_PASSWORD}@127.0.0.1:27017/admin --mongodb.tls-cert /etc/ssl/mongod/mongod.pem --mongodb.tls-ca /etc/ssl/mongod/ca.pem'
        ],  # flake8: noqa
        ports=[metrics_port],
        resources=metrics_resources,
        volume_mounts=[mongodb_tls_volumemount],
        env=[metrics_username_env_var, metrics_password_env_var])

    statefulset.spec.template.spec.containers = [
        mongodb_container, metrics_container
    ]

    ca_volume = client.V1Volume(name='mongo-ca',
                                secret=client.V1SecretVolumeSource(
                                    secret_name='{}-ca'.format(name),
                                    items=[
                                        client.V1KeyToPath(key='ca.pem',
                                                           path='ca.pem'),
                                        client.V1KeyToPath(key='ca-key.pem',
                                                           path='ca-key.pem')
                                    ]))
    tls_volume = client.V1Volume(name='mongo-tls',
                                 empty_dir=client.V1EmptyDirVolumeSource())
    data_volume = client.V1Volume(name='mongo-data',
                                  empty_dir=client.V1EmptyDirVolumeSource())
    statefulset.spec.template.spec.volumes = [
        ca_volume, tls_volume, data_volume
    ]

    # Init container
    tls_init_ca_volumemount = client.V1VolumeMount(
        name='mongo-ca', read_only=True, mount_path='/etc/ssl/mongod-ca')
    tls_init_mongodb_tls_volumemount = client.V1VolumeMount(
        name='mongo-tls', read_only=False, mount_path='/etc/ssl/mongod')
    tls_init_container = client.V1Container(
        name="cert-init",
        image="quay.io/kubestack/mongodb-init:latest",
        volume_mounts=[
            tls_init_ca_volumemount, tls_init_mongodb_tls_volumemount
        ],
        env=[
            client.V1EnvVar(
                name='METADATA_NAME',
                value_from=client.V1EnvVarSource(
                    field_ref=client.V1ObjectFieldSelector(
                        api_version='v1', field_path='metadata.name'))),
            client.V1EnvVar(
                name='NAMESPACE',
                value_from=client.V1EnvVarSource(
                    field_ref=client.V1ObjectFieldSelector(
                        api_version='v1', field_path='metadata.namespace')))
        ],
        command=["ansible-playbook", "member-cert.yml"])

    statefulset.spec.template.spec.init_containers = [tls_init_container]

    return statefulset