Использование инфраструктуры как кода (IaC) для определения вашей инфраструктуры помогает избежать несогласованности развертывания, повысить производительность разработчиков и снизить затраты. Мы в ScaleSec любим использовать IaC для защиты облака — ознакомьтесь с сообщениями в нашем блоге об использовании Terraform для Политик управления службами организаций AWS и Управления службами Google Cloud VPC. В этом посте мы рассмотрим Pulumi и то, как мы можем разработать хорошо спроектированную инфраструктуру в виде кода в Amazon Web Services (AWS) с использованием TypeScript.

О хорошо спроектированной инфраструктуре

Инфраструктура с продуманной архитектурой предназначена для демонстрации нескольких ключевых качеств, а именно: безопасность, надежность, высокая производительность, экономичность и превосходная операционная эффективность. AWS предоставила обширную документацию по Well-Architected Framework, которая поощряет лучшие практики инфраструктуры, перечисленные выше и рассмотренные в этой записи блога. Наличие хорошо спроектированной инфраструктуры гарантирует целостный подход к архитектуре и проектированию облачных рабочих нагрузок.

Почему Пулуми?

Pulumi позволяет определять IaC на языке программирования общего назначения, что открывает ряд возможностей для объявления инфраструктуры, такой как циклы, функции, классы и управление пакетами. Это достигается за счет использования модели желаемого состояния для управления инфраструктурой, очень похожей на поведение других решений IaC, таких как Terraform и AWS CloudFormation. Он работает во всех основных публичных облаках и даже может адаптировать провайдеров Terraform.

Как помогает пешеходный переход Пулуми

Pulumi Crosswalk доступен для AWS и Kubernetes. Crosswalk — это набор передовых методов, которые упрощают выполнение общих задач инфраструктуры и делают их более безопасными. Таким образом, он помогает обеспечить защиту приложений, встраивая стандарты безопасности в конфигурации по умолчанию.

Примеры хорошо спроектированной инфраструктуры как кода

Well-Architected Framework состоит из пяти столпов, и ниже приведен пример того, как инфраструктура как код может использоваться для достижения целей по каждому столпу каркаса.

Функциональное совершенство

Pulumi Crosswalk для Kubernetes был недавно выпущен и совместим с платформами Kubernetes во всех трех основных общедоступных облаках: AWS, GCP и Azure. Поскольку эта конкретная статья посвящена лучшим практикам в AWS, Elastic Kubernetes Service (EKS) будет продемонстрирована в примере Operational Excellence, хотя поддержка также существует для Google Kubernetes Engine (GKE) и Azure Kubernetes Service (AKS).

Выполнение операций в виде кода важно для операционного совершенства организации. Это означает, что вы можете обрабатывать инфраструктуру, приложения и операции, связанные с ними, с помощью кода и можете использовать аналогичные инструменты и методы для проектирования и разработки решений. Pulumi помогает облегчить это, позволяя выражать инфраструктуру, код приложения и развертывание на общем языке программирования, например TypeScript.

Для начала мы начнем с создания репозитория для образа Docker, который мы хотим создать и в конечном итоге развернуть в кластере Kubernetes. Помимо импорта необходимой библиотеки, создание нового реестра эластичных контейнеров (ECR) — это однострочный процесс по умолчанию index.ts:

import * as awsx from "@pulumi/awsx";

const repo = new awsx.ecr.Repository("repository");

Выполнение pulumi up создаст репозиторий с политикой жизненного цикла по умолчанию, в которой будет храниться не более одного непомеченного образа, что является лучшей практикой для репозиториев Docker. Теперь давайте создадим очень простой Dockerfile для сборки в том же каталоге, что и наш код Pulumi:

FROM busybox:latest
CMD ["date"]

Теперь давайте добавим код в наш файл index.ts для создания образа Docker:

const dockerImage = repo.buildAndPushImage(`./`);

И запустите pulumi up, который выполняет docker build за кулисами и помещает этот вновь созданный образ в репозиторий. С помощью всего нескольких строк кода у нас теперь есть способ создать и сохранить образ докера в репозиторий ECR. Теперь давайте настроим нашу плоскость управления EKS и экспортируем сгенерированный kubeconfig с новым импортом и парой строк:

import * as eks from "@pulumi/eks";
const cluster = new eks.Cluster("cluster");
export const kubeconfig = cluster.kubeconfig;

Это создаст кластер EKS с хорошими настройками по умолчанию, такими как использование двух узлов размером t2.medium с AWS IAM Authenticator для использования IAM для безопасного доступа к вашему кластеру. Кроме того, сгенерированный вывод можно использовать с kubectl CLI. Теперь, когда у нас есть кластер и репозиторий докеров с сохраненным созданным образом, давайте создадим развертывание Kubernetes, добавив это в наш файл TypeScript:

import * as k8s from "@pulumi/kubernetes";
// Create a k8s provider
const provider = new k8s.Provider("provider", {
    kubeconfig: cluster.kubeconfig,
});

// Create a Deployment of the built container
const appLabels = { app: dockerImage };
const appDeployment = new k8s.apps.v1.Deployment("app", {
    spec: {
        selector: { matchLabels: appLabels },
        replicas: 1,
        template: {
            metadata: { labels: appLabels },
            spec: {
                containers: [{
                    name: dockerImage,
                    image: dockerImage,
                    ports: [{name: "http", containerPort: 80}],
                }],
            }
        },
    }
}, { provider: provider });

И с pulumi up у нас теперь есть busybox, работающий в нашем кластере Kubernetes. Этот пример демонстрирует, что мы можем выразить нашу инфраструктуру (кластер ECR и Kubernetes), процесс сборки (docker build/docker push) и развертывание (через Kubernetes Deployment) лаконичным и единообразным образом. Это помогает облегчить оперативный доступ за счет использования надежной инфраструктуры в качестве кода.

Безопасность

AWS Identity and Access Management (IAM) позволяет облачным практикам безопасно получать доступ к сервисам и ресурсам AWS. Используя IAM, можно разрешать и запрещать доступ к ресурсам AWS с помощью разрешений. Pulumi, используя возможности языка программирования общего назначения, может упростить создание и работу с языком политик IAM (JSON). Отличным примером этого является использование преимущества строгой типизации TypeScript для проверки атрибутов с опечатками во время компиляции для предотвращения ошибок. Это означает, что неправильные конфигурации могут быть обнаружены при компиляции кода во время pulumi up, а не в ожидании ошибки API AWS или, что еще хуже, при обнаружении ошибки после развертывания в среде, что приводит к неправильным конфигурациям безопасности в развернутых политиках IAM.

Это может помочь сэкономить время, добавить дополнительную удобную для разработчика проверку инфраструктуры кодирования внутри IDE (сохранить безопасность смены) и обеспечить безопасное управление ролями, пользователями, группами и политиками IAM. Вот пример использования интерфейса PolicyDocument для добавления строгой проверки в политику доверия IAM STS для EC2:

import * as aws from "@pulumi/aws";

const policy: aws.iam.PolicyDocument = {
    Version: "2012-10-17",
    Statement: [
        {
            Action: "sts:AssumeRole",
            Principal: {
               Service: "ec2.amazonaws.com"
            },
            Effect: "Allow",
            Sid: "",
        },
    ],
};

Надежность

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

Существует много способов добиться надежности при разработке архитектуры для облака. Одной из основных технологий, которая приходит на ум, является использование контейнеров. Контейнеры отделяют приложения от операционной системы и инфраструктуры, в которой они работают, обеспечивая приемлемый ответ на старую поговорку «это работает на моей машине».

Чтобы контейнеры были максимально эффективными в облаке, необходим оркестратор контейнеров. Оркестраторы контейнеров помогают на этапах жизненного цикла контейнера, включая подготовку, планирование и масштабирование/выделение ресурсов. Сервис Amazon Elastic Container Service (ECS) помогает в этом, предоставляя возможность делать все вышеперечисленное и многое другое, даже запускать контейнеры в бессерверном режиме через AWS Fargate. ECS хорошо интегрируется с другими сервисами AWS, такими как Elastic Load Balancing (ELB), который обеспечивает дополнительную надежность в облаке за счет автоматического распределения трафика приложений между несколькими целевыми объектами с минимальными затратами на управление.

Pulumi Crosswalk имеет первоклассную поддержку как ECS, так и ELB, что будет продемонстрировано в следующем примере с использованием nginx. Балансировщик нагрузки приложений (ALB) легко настроить с помощью приведенного ниже кода:

import * as awsx from "@pulumi/awsx";

// Create a load balancer that listens on port 80 (HTTP)
const alb = new awsx.lb.ApplicationListener("nginx", { port: 80 });

На lb, который мы определили выше, можно ссылаться в кластере AWS ECS с помощью Fargate. В следующем примере мы запустим три экземпляра nginx в нашем бессерверном кластере Docker.

const service = new awsx.ecs.FargateService("nginx", {
    taskDefinitionArgs: {
        containers: {
            nginx: {
                image: "nginx",
                portMappings: [ alb ],
            },
        },
    },
    desiredCount: 3,
});

В конце нашего файла мы экспортируем hostname балансировщика нагрузки, чтобы мы могли ссылаться на него для посещения службы.

export const url = alb.endpoint.hostname;

После запуска pulumi up мы можем получить доступ к работающей службе nginx, используя вывод стека Pulumi в командной строке: curl http://$(pulumi stack output url). Больше примеров настройки ECS-кластера в Pulumi можно найти в их документации. Теперь у нас есть кластер, поддерживаемый AWS Fargate, что возлагает на AWS ответственность за управление виртуальными машинами, на которых будут работать наши контейнеры, и в целом способствует надежности рабочей нагрузки.

Эффективность производительности

Важной частью поддержания производительности облачной среды является возможность ее мониторинга. В белой книге платформы AWS Well Architected есть целый раздел, посвященный мониторингу, касающийся компонента Эффективность производительности.

Pulumi Crosswalk для CloudWatch допускает автоматическую безопасность по умолчанию, включая автоматические группы журналов (если они не указаны, они будут созданы автоматически) и разумную политику хранения. Добавить ведение журнала Cloudwatch из контейнера относительно просто, основываясь на приведенном выше примере ECS Fargate. Вот полный код для этого:

import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";

const alb = new awsx.lb.ApplicationListener("nginx", { port: 80 });

const logGroup = new aws.cloudwatch.LogGroup("logs");

const service = new awsx.ecs.FargateService("nginx", {
    taskDefinitionArgs: {
        containers: {
            nginx: {
                image: "nginx",
                portMappings: [ alb ],
            },
        },
    },
    desiredCount: 3,
});

export const url = alb.endpoint.hostname;

Очень удобная функция заключается в том, что с помощью команды pulumi logs -f после развертывания этого кода можно отслеживать эти журналы в командной строке в режиме реального времени. Если мы сделаем это с помощью приведенного выше кода, входящий трафик на сервер nginx, включая проверки работоспособности балансировщика нагрузки и посещения страницы по умолчанию, можно будет проверить (пример вывода ниже):

 2019-11-27T20:18:48.982-05:00[                 nginx-0bbf916] 172.31.15.119 - - [28/Nov/2019:01:18:48 +0000] "GET / HTTP/1.1" 200 612 "-" "ELB-HealthChecker/2.0" "-"
 2019-11-27T20:18:50.418-05:00[                 nginx-0bbf916] 172.31.15.119 - - [28/Nov/2019:01:18:50 +0000] "GET / HTTP/1.1" 200 612 "-" "ELB-HealthChecker/2.0" "-"
 2019-11-27T20:18:52.544-05:00[                 nginx-0bbf916] 172.31.15.119 - - [28/Nov/2019:01:18:52 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10Deployment1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" "127.0.0.1"
 2019-11-27T20:18:53.405-05:00[                 nginx-0bbf916] 172.31.47.29 - - [28/Nov/2019:01:18:53 +0000] "GET / HTTP/1.1" 200 612 "-" "ELB-HealthChecker/2.0" "-"

В этом примере мы показываем, как Pulumi Crosswalk может помочь нам беспрепятственно отслеживать код, который мы развертываем, что также можно применять в ситуациях, когда требуется мониторинг производительности или устранение неполадок.

Оптимизация затрат

Одной из составляющих оптимизации затрат в облаке является использование эластичности, предоставляемой для масштабирования или отключения неиспользуемых служб. Это можно сделать в AWS, воспользовавшись функциями автоматического масштабирования и автоматического масштабирования по расписанию. Например, если мы хотим масштабировать экземпляры в субботу, а затем уменьшать во вторник, этого можно легко добиться с помощью Pulumi Crosswalk:

import * as awsx from "@pulumi/awsx";

const asg = new awsx.autoscaling.AutoScalingGroup("asg", {
    templateParameters: { minSize: 1 },
    launchConfigurationArgs: { instanceType: "t3.nano" },
});

asg.scaleOnSchedule("scaleUpOnFriday", {
    desiredCapacity: 3,
    recurrence: { dayOfWeek: "Saturday" },
});

asg.scaleOnSchedule("scaleDownOnTuesday", {
    desiredCapacity: 1,
    recurrence: { dayOfWeek: "Tuesday" },
});

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

Вывод

Мы продемонстрировали, как можно использовать инфраструктуру как код для создания хорошо спроектированных рабочих нагрузок в AWS. Мы сделали это, выбрав Pulumi Crosswalk в качестве решения и имея примеры для каждого элемента хорошо продуманной структуры. Очевидно, что для достижения целей, изложенных в структуре, требуется гораздо больше, чем то, что было продемонстрировано в этом посте, однако эта статья демонстрирует, как использование встроенных передовых методов и дополнительных ограждений в инфраструктуре в качестве кода может помочь достичь этих целей в облаке. Позвольте нам помочь вам добраться туда!

Информация, представленная в этой статье, актуальна по состоянию на 18 декабря 2019 г. Следите за новыми статьями и обновлениями в блоге ScaleSec.

О нас

ScaleSec – это опытный малый бизнес (SDVOSB), которому недоступна служба, для обеспечения облачной безопасности и соблюдения нормативных требований, который помогает новаторам удовлетворять требования своих самых придирчивых клиентов. Мы специализируемся на проектировании облачной безопасности и соблюдении облачных требований. Наша команда экспертов помогает клиентам справиться со сложными задачами в области облачной безопасности, начиная с фундамента и заканчивая внедрением, подготовкой к аудиту и не только. Узнайте больше на https://scalesec.com.

Мы нанимаем"!