typeProviders с частными кластерами GKE - PullRequest
0 голосов
/ 03 июля 2019

Я новичок в облачном менеджере Google (GCM) и пишу код для практики. Я прочитал несколько интересных статей, в которых подробно описывается, как я могу использовать deploymanager.v2beta.typeprovider для расширения GCM и использования его для настройки самих объектов Kubernetes в качестве дополнительного развертывания. Это очень привлекательное поведение для расширения и, кажется, открывает большие возможности для расширения декларативной автоматизации любого API, что здорово.

Я пытаюсь создать кластер GKE частного узла / публичной конечной точки, который управляется пользовательскими ресурсами typeProvider, соответствующими вызовам API GKE. Кажется, что кластер GKE общедоступного узла / общедоступной конечной точки является единственным способом поддержки пользовательских провайдеров типов GCM, и это кажется неправильным, учитывая возможную конфигурацию GKE частного узла / общедоступной конечной точки.

Кажется, было бы странно не иметь deploymanager.v2beta.typeprovider для поддержки конфигурации GKE частного узла / публичной конечной точки.

в сторону ... Я чувствую, что частный узел / частная конечная точка / облачная конечная точка, чтобы выставить ее в соответствии с требованием конечной точки общедоступного API GCM typeProvider, также должна быть допустимой архитектурой, но мне еще предстоит протестировать.

Используя следующий код

def GenerateConfig(context):
    # Some constant type vars that are not really
    resources = []
    outputs = []
    gcp_type_provider = 'deploymentmanager.v2beta.typeProvider'
    extension_prefix = 'k8s'
    api_version = 'v1'
    kube_initial_auth = {
        'username': 'luis',
        'password': 'letmeinporfavors',
        "clientCertificateConfig": {
            'issueClientCertificate': True
        }
    }

    # EXTEND API TO CONTROL KUBERNETES BEGIN
    kubernetes_exposed_apis = [
        {
            'name': '{}-{}-api-v1-type'.format(
                context.env['deployment'],
                extension_prefix
            ),
            'endpoint': 'api/v1'
        },
        {
            'name': '{}-{}-apps-v1-type'.format(
                context.env['deployment'],
                extension_prefix
            ),
            'endpoint': 'apis/apps/v1'
        },
        {
            'name': '{}-{}-rbac-v1-type'.format(
                context.env['deployment'],
                extension_prefix
            ),
            'endpoint': 'apis/rbac.authorization.k8s.io/v1'
        },
        {
            'name': '{}-{}-v1beta1-extensions-type'.format(
                context.env['deployment'],
                extension_prefix
            ),
            'endpoint': 'apis/extensions/v1beta1'
        }
    ]
    for exposed_api in kubernetes_exposed_apis:
        descriptor_url = 'https://{}/swaggerapi/{}'.format(
            '$(ref.{}-k8s-cluster.endpoint)'.format(
                context.env['deployment']
            ),
            exposed_api['endpoint']
        )
        resources.append(
            {
                'name': exposed_api['name'],
                'type': gcp_type_provider,
                'properties': {
                    'options': {
                        'validationOptions': {
                            'schemaValidation': 'IGNORE_WITH_WARNINGS'
                        },
                        'inputMappings': [
                            {
                                'fieldName': 'name',
                                'location': 'PATH',
                                'methodMatch': '^(GET|DELETE|PUT)$',
                                'value': '$.ifNull($.resource.properties.metadata.name, $.resource.name)'

                            },
                            {
                                'fieldName': 'metadata.name',
                                'location': 'BODY',
                                'methodMatch': '^(PUT|POST)$',
                                'value': '$.ifNull($.resource.properties.metadata.name, $.resource.name)'
                            },
                            {
                                'fieldName': 'Authorization',
                                'location': 'HEADER',
                                'value': '$.concat("Bearer ", $.googleOauth2AccessToken())'
                            }
                        ],
                    },
                    'descriptorUrl': descriptor_url
                },
            }
        )
    # EXTEND API TO CONTROL KUBERNETES END

    # NETWORK DEFINITION BEGIN
    resources.append(
        {
            'name': "{}-network".format(context.env['deployment']),
            'type': "compute.{}.network".format(api_version),
            'properties': {
                'description': "{} network".format(context.env['deployment']),
                'autoCreateSubnetworks': False,
                'routingConfig': {
                    'routingMode': 'REGIONAL'
                }
            },
        }
    )

    resources.append(
        {
            'name': "{}-subnetwork".format(context.env['deployment']),
            'type': "compute.{}.subnetwork".format(api_version),
            'properties': {
                'description': "{} subnetwork".format(
                    context.env['deployment']
                ),
                'network': "$(ref.{}-network.selfLink)".format(
                    context.env['deployment']
                ),
                'ipCidrRange': '10.64.1.0/24',
                'region': 'us-east1',
                'privateIpGoogleAccess': True,
                'enableFlowLogs': False,
            }
        }
    )
    # NETWORK DEFINITION END

    # EKS DEFINITION BEGIN
    resources.append(
        {
            'name': "{}-k8s-cluster".format(context.env['deployment']),
            'type': "container.{}.cluster".format(api_version),
            'properties': {
                'zone': 'us-east1-b',
                'cluster': {
                    'description': "{} kubernetes cluster".format(
                        context.env['deployment']
                    ),
                    'privateClusterConfig': {
                        'enablePrivateNodes': False,
                        'masterIpv4CidrBlock': '10.0.0.0/28'
                    },
                    'ipAllocationPolicy': {
                        'useIpAliases': True
                    },
                    'nodePools': [
                        {
                            'name': "{}-cluster-pool".format(
                                context.env['deployment']
                            ),
                            'initialNodeCount': 1,
                            'config': {
                                'machineType': 'n1-standard-1',
                                'oauthScopes': [
                                    'https://www.googleapis.com/auth/compute',
                                    'https://www.googleapis.com/auth/devstorage.read_only',
                                    'https://www.googleapis.com/auth/logging.write',
                                    'https://www.googleapis.com/auth/monitoring'
                                ],
                            },
                            'management': {
                                'autoUpgrade': False,
                                'autoRepair': True
                            }
                        }],
                    'masterAuth': kube_initial_auth,
                    'loggingService': 'logging.googleapis.com',
                    'monitoringService': 'monitoring.googleapis.com',
                    'network': "$(ref.{}-network.selfLink)".format(
                        context.env['deployment']
                    ),
                    'clusterIpv4Cidr': '10.0.0.0/14',
                    'subnetwork': "$(ref.{}-subnetwork.selfLink)".format(
                        context.env['deployment']
                    ),
                    'enableKubernetesAlpha': False,
                    'resourceLabels': {
                        'purpose': 'expiramentation'
                    },
                    'networkPolicy': {
                        'provider': 'CALICO',
                        'enabled': True
                    },
                    'initialClusterVersion': 'latest',
                    'enableTpu': False,
                }
            }
        }
    )
    outputs.append(
        {
            'name': '{}-cluster-endpoint'.format(
                context.env['deployment']
            ),
            'value': '$(ref.{}-k8s-cluster.endpoint)'.format(
                context.env['deployment']
            ),
        }
    )
    # EKS DEFINITION END

    # bring it all together
    template = {
        'resources': resources,
        'outputs': outputs
    }

    # give it to google
    return template


if __name__ == '__main__':
    GenerateConfig({})

Также я отмечу последующий шаблон hello world, в котором используются созданные выше поставщики типов.

def current_config():
    '''
    get the current configuration
    '''
    return {
        'name': 'atrium'
    }


def GenerateConfig(context):
    resources = []
    conf = current_config()
    resources.append(
        {
            'name': '{}-svc'.format(conf['name']),
            'type': "{}/{}-k8s-api-v1-type:/api/v1/namespaces/{}/pods".format(
                context.env['project'],
                conf['name'],
                '{namespace}'
            ),
            'properties': {
                'namespace': 'default',
                'apiVersion': 'v1',
                'kind': 'Pod',
                'metadata': {
                    'name': 'hello-world',
                },
                'spec': {
                    'restartPolicy': 'Never',
                    'containers': [
                        {
                            'name': 'hello',
                            'image': 'ubuntu:14.04',
                            'command': ['/bin/echo', 'hello', 'world'],
                        }
                    ]
                }
            }
        }
    )

    template = {
        'resources': resources,
    }

    return template


if __name__ == '__main__':
    GenerateConfig({})

Если я оставлю enablePrivateNodes как False

                    'privateClusterConfig': {
                        'enablePrivateNodes': False,
                        'masterIpv4CidrBlock': '10.0.0.0/28'
                    }

Я получаю это в ответ

~/code/github/gcp/expiramentation/atrium_gcp_infra 24s
❯ bash atrium/recycle.sh
Waiting for delete [operation-1562105370163-58cb9ffb0b7b8-7479dd98-275c6b14]...done.
Delete operation operation-1562105370163-58cb9ffb0b7b8-7479dd98-275c6b14 completed successfully.
Waiting for delete [operation-1562105393399-58cba01134528-be47dc30-755cb106]...done.
Delete operation operation-1562105393399-58cba01134528-be47dc30-755cb106 completed successfully.
The fingerprint of the deployment is IiWcrdbZA5MedNlJLIicOg==
Waiting for create [operation-1562105786056-58cba187abee2-5d761e87-b446baca]...done.
Create operation operation-1562105786056-58cba187abee2-5d761e87-b446baca completed successfully.
NAME                                TYPE                                   STATE      ERRORS  INTENT
atrium-k8s-api-v1-type              deploymentmanager.v2beta.typeProvider  COMPLETED  []
atrium-k8s-apps-v1-type             deploymentmanager.v2beta.typeProvider  COMPLETED  []
atrium-k8s-cluster                  container.v1.cluster                   COMPLETED  []
atrium-k8s-rbac-v1-type             deploymentmanager.v2beta.typeProvider  COMPLETED  []
atrium-k8s-v1beta1-extensions-type  deploymentmanager.v2beta.typeProvider  COMPLETED  []
atrium-network                      compute.v1.network                     COMPLETED  []
atrium-subnetwork                   compute.v1.subnetwork                  COMPLETED  []
The fingerprint of the deployment is QJ2NS5EhjemyQJThUWYNHA==
Waiting for create [operation-1562106179055-58cba2fe76fe7-957ef7a6-f55257bb]...done.
Create operation operation-1562106179055-58cba2fe76fe7-957ef7a6-f55257bb completed successfully.
NAME        TYPE                                                                      STATE      ERRORS  INTENT
atrium-svc  atrium-244423/atrium-k8s-api-v1-type:/api/v1/namespaces/{namespace}/pods  COMPLETED  []

~/code/github/gcp/expiramentation/atrium_gcp_infra 13m 48s

это хороший ответ, и мой пользовательский ресурс typeProvider создается правильно с использованием API моего только что созданного кластера.

Если я сделаю этот кластер иметь частные узлы, однако ... с

                     'privateClusterConfig': {
                         'enablePrivateNodes': True,
                         'masterIpv4CidrBlock': '10.0.0.0/28'
                     },

Я терплю неудачу с

~/code/github/gcp/expiramentation/atrium_gcp_infra 56s
❯ bash atrium/recycle.sh
Waiting for delete [operation-1562106572016-58cba47538c93-d34c17fc-8b863765]...done.
Delete operation operation-1562106572016-58cba47538c93-d34c17fc-8b863765 completed successfully.
Waiting for delete [operation-1562106592237-58cba4888184f-a5bc3135-4e662eed]...done.
Delete operation operation-1562106592237-58cba4888184f-a5bc3135-4e662eed completed successfully.
The fingerprint of the deployment is dk5nh_u5ZFFvYO-pCXnFBg==
Waiting for create [operation-1562106901442-58cba5af62f25-8b0e380f-3687aebd]...done.
Create operation operation-1562106901442-58cba5af62f25-8b0e380f-3687aebd completed successfully.
NAME                                TYPE                                   STATE      ERRORS  INTENT
atrium-k8s-api-v1-type              deploymentmanager.v2beta.typeProvider  COMPLETED  []
atrium-k8s-apps-v1-type             deploymentmanager.v2beta.typeProvider  COMPLETED  []
atrium-k8s-cluster                  container.v1.cluster                   COMPLETED  []
atrium-k8s-rbac-v1-type             deploymentmanager.v2beta.typeProvider  COMPLETED  []
atrium-k8s-v1beta1-extensions-type  deploymentmanager.v2beta.typeProvider  COMPLETED  []
atrium-network                      compute.v1.network                     COMPLETED  []
atrium-subnetwork                   compute.v1.subnetwork                  COMPLETED  []
The fingerprint of the deployment is 4RnscwpcYTtS614VXqtjRg==
Waiting for create [operation-1562107350345-58cba75b7e680-f548a69f-1a85f105]...failed.
ERROR: (gcloud.deployment-manager.deployments.create) Error in Operation [operation-1562107350345-58cba75b7e680-f548a69f-1a85f105]: errors:
- code: ERROR_PROCESSING_REQUEST
  message: 'Error fetching URL https://10.0.0.2:443/api/v1/namespaces/default/pods,
    reason: ERROR_EXCLUDED_IP'

10.0.0.2, похоже, является частной конечной точкой моего кластера. Мне трудно отследить, где я могу переопределить хост https://10.0.0.2:443/api/v1/namespaces/default/pods url, чтобы он пытался связаться с publicEndpoint, а не с privateEndpoint.

Если бы этот вызов был направлен на общедоступную конечную точку, он, я полагаю, был бы успешно создан. Интересно отметить, что объявления typeProvider в descriptorUrl пытаются попасть в publicEndpoint кластера и добиваются успеха в этом. Однако, несмотря на это указание, создание реальных ресурсов API, таких как пример hello world, пытается взаимодействовать с частной конечной точкой.

Я чувствую, что это поведение должно быть где-то переопределено, но я не могу найти эту подсказку.

Я пробовал как рабочую конфигурацию открытого узла, так и нерабочую конфигурацию частного узла

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...