詳細検索

AWS CodePipeline + EKS Action: A maneira mais fácil de implantar containers até agora!

Avatar
por Jatin Mehrotra

AWS CodePipeline + EKS Action: A maneira mais fácil de implantar containers até agora!
Traduzido do English • Ver original

A equipe CodePipeline da Amazon Web Services (AWS) simplificou a sobrecarga operacional dos desenvolvedores e engenheiros DevOps e agilizou o processo de implantação no EKS ao introduzir uma ação CodePipeline para implantar diretamente no seu cluster EKS.

Por que isso importa para você?

Antes, se eu tivesse que implantar recursos no EKS usando a abordagem DevOps, tinha que gerenciar o projeto de codebuild, permissões para acessar EKS, kubectl, comandos helm, outros comandos horríveis de shell, e ainda assim não ficava perfeito de uma vez só.

Testei isso hoje, então deixe-me mostrar como você pode simplificar seu pipeline de implantação para EKS em 100%, diga adeus ao codebuild e remova todo o processo, scripts e comandos complexos!!

Arquitetura

Pré-requisitos

  • Cluster EKS com endpoint público.
  • Kubernetes resource like deployment.yaml file
  • Você também pode fazer o quadro, se quiser.

Nota: Se você quiser tentar esta atualização com o EKS Private Endpoint, confira este blog do AWS Hero Arshad Zackeriya.

Qualquer que você preferir, disponibilizei ambos (helm chart e deployment.yaml) neste repositório.

Nos Bastidores

No caso do arquivo de manifestos do Kubernetes

 

  • Essa ação registra no EKS cluster, define o contexto kubeconfig
  • Installs kubectl
  • Aplica manifestos Kubernetes
  • Recursos de implementação

No caso do leme gráfico

codepipeline bts with helm chart
  • Essa ação registra no EKS cluster, define o contexto kubeconfig
  • Instala o leme
  • Gráficos Instal Helm

Criar um cluster EKS

Seu cluster pode ser público ou privado (incluindo aqueles em VPCs privadas). O pipeline estabelecerá automaticamente uma conexão com sua rede privada para implantar sua aplicação container, sem necessidade de infraestrutura adicional.

eks.tf

# EKS cluster

módulo "eks" { 
fonte = "terraform-aws-modules/eks/aws" 
versão = "~> 20.31" 

cluster_name = local.cluster_name
cluster_version = "1,32" 
cluster_endpoint_public_access = verdadeiro


vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets

cluster_compute_config = { 
ativado = verdadeiro
node_pools = ["uso geral"]
  }

# Entrada de acesso ao cluster
# Para adicionar a identidade atual do chamador como administrador
enable_cluster_creator_admin_permissions = verdadeiro


tags = { 
Ambiente = "dev" 
Terraformação = "verdadeiro" 
  }
}

vpc.tf

módulo "vpc" { 
fonte = "terraform-aws-modules/vpc/aws" 
versão = "5.19.0" 

nome = "codepipeline-eks-action" 
cidr = "10.0.0.0/16" 

azs = ["EUA-Leste-1A", "EUA-Leste-1B"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.4.0/24", "10.0.5.0/24"]

enable_nat_gateway = verdadeiro
single_nat_gateway = verdadeiro
one_nat_gateway_per_az = falso

enable_dns_hostnames = verdadeiro
enable_dns_support = verdadeiro

public_subnet_tags = { 
"kubernetes.io/role/elb" = "1" 
  }
private_subnet_tags = { 
"kubernetes.io/role/internal-elb" = "1" 
  }

tags = { 
Ambiente = "terraform-playground" 
  }
}

pod_identity.tf

data "aws_iam_policy_document" "allow_pod_identity" { 
afirmação { 
efeito = "Permitir" 

diretores { 
tipo = "Serviço" 
identificadores = ["pods.eks.amazonaws.com"]
    }

ações = [ 
"sts:AssumeRole", 
"sts:TagSession" 
    ]
  }
}

recurso "aws_iam_role" "read_ecr" { 
nome = "read-ecr-role" 
assume_role_policy = data.aws_iam_policy_document.allow_pod_identity.json
}

recurso "aws_iam_role_policy_attachment" "read_ecr" { 
função = aws_iam_role.read_ecr.name
policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" 
}

recurso "aws_eks_pod_identity_association" "read_ecr" { 
cluster_name = local.cluster_name
namespace = "padrão" 
service_account = "ecr-sa" 
role_arn = aws_iam_role.read_ecr.arn
}

 

Nota: Estou usando a identidade do pod com permissão do repositório ECR para obter a imagem ecr para deployment.yaml.

Se você quiser código completo para o cluster, pode seguir este repositório

Criar pipeline com ação de implantação do EKS

Caso 1: quando a configuração kubectl é usada.

Estou usando o código-fonte como GitHub usando a conexão de início do código e o código reside neste repositório

codepipeline helm config

  • Selecione o cluster
  • Forneça o caminho para seu arquivo deployment.yaml (no meu caso, é o arquivo deployment.yaml )

Caso 2: Quando o mapa de Helm é usado

codepipeline helm config
  • Insira o nome do lançamento
  • Insira o gráfico do helm (no meu caso é o gráfico de teste)

Passo importante

Nota: Uma vez que o pipeline é criado, você precisa editar o papel de serviço do pipeline ou atualizar o existente e adicionar as seguintes permissões para evitar erros.

{ 
"Declaração": [ 
        { 
"Ação": [ 
"iam:PassRole" 
            ], 
"Resource": "*", 
"Efeito": "Permitir", 
"Condição": { 
"StringEqualsIfExists": { 
"iam:PassedToService": [ 
"cloudformation.amazonaws.com", 
"elasticbeanstalk.amazonaws.com", 
"ec2.amazonaws.com", 
"ecs-tasks.amazonaws.com" 
                    ]
                }
            }
        }, 
        { 
"Ação": [ 
"codecommit:CancelUploadArchive", 
"codecommit:GetBranch", 
"codecommit:GetCommit", 
"codecommit:GetRepository", 
"codecommit:GetUploadArchiveStatus", 
"codecommit:UploadArchive" 
            ], 
"Resource": "*", 
"Efeito": "Permitir" 
        }, 
        { 
"Ação": [ 
"codedeploy:CreateDeployment", 
"codedeploy:GetApplication", 
"codedeploy:GetApplicationRevision", 
"codedeploy:GetDeployment", 
"codedeploy:GetDeploymentConfig", 
"codedeploy:RegisterApplicationRevision" 
            ], 
"Resource": "*", 
"Efeito": "Permitir" 
        }, 
        { 
"Ação": [ 
"codestar-connections:UseConnection" 
            ], 
"Resource": "*", 
"Efeito": "Permitir" 
        }, 
        { 
"Ação": [ 
"pé de feijão elástico:*", 
"ec2:*", 
"equilíbrio de carga elástica:*", 
"autoscaling:*", 
"Cloudwatch:*", 
"s3:*", 
"sns:*", 
"formação de nuvens:*", 
"rds:*", 
"sqs:*", 
"ECS:*" 
            ], 
"Resource": "*", 
"Efeito": "Permitir" 
        }, 
        { 
"Ação": [ 
"lambda:InvokeFunction", 
"lambda:ListFunctions" 
            ], 
"Resource": "*", 
"Efeito": "Permitir" 
        }, 
        { 
"Ação": [ 
"opsworks:CreateDeployment", 
"opsworks:DescribeApps", 
"opsworks:DescribeCommands", 
"opsworks:DescreveImplantações", 
"opsworks:DescribeInstances", 
"opsworks:DescribeStacks", 
"opsworks:UpdateApp", 
"opsworks:UpdateStack" 
            ], 
"Resource": "*", 
"Efeito": "Permitir" 
        }, 
        { 
"Ação": [ 
"cloudformation:CreateStack", 
"cloudformation:DeleteStack", 
"cloudformation:DescribeStacks", 
"cloudformation:UpdateStack", 
"cloudformation:CreateChangeSet", 
"cloudformation:DeleteChangeSet", 
"cloudformation:DescribeChangeSet", 
"cloudformation:ExecuteChangeSet", 
"cloudformation:SetStackPolicy", 
"cloudformation:ValidateTemplate" 
            ], 
"Resource": "*", 
"Efeito": "Permitir" 
        }, 
        { 
"Ação": [ 
"codebuild:BatchGetBuilds", 
"codebuild:StartBuild", 
"codebuild:BatchGetBuildBatches", 
"codebuild:StartBuildBatch" 
            ], 
"Resource": "*", 
"Efeito": "Permitir" 
        }, 
        { 
"Efeito": "Permitir", 
"Ação": [ 
"devicefarm:ListProjects", 
"fazenda de dispositivos:ListDevicePools", 
"devicefarm:GetRun", 
"devicefarm:GetUpload", 
"devicefarm:CreateUpload", 
"devicefarm:ScheduleRun" 
            ], 
"Recurso": "*" 
        }, 
        { 
"Efeito": "Permitir", 
"Ação": [ 
"servicecatalog:ListProvisioningArtifacts", 
"servicecatalog:CreateProvisioningArtifact", 
"servicecatalog:DescribeProvisioningArtifact", 
"servicecatalog:DeleteProvisioningArtifact", 
"servicecatalog:UpdateProduct" 
            ], 
"Recurso": "*" 
        }, 
        { 
"Efeito": "Permitir", 
"Ação": [ 
"cloudformation:ValidateTemplate" 
            ], 
"Recurso": "*" 
        }, 
        { 
"Efeito": "Permitir", 
"Ação": [ 
"ecr:DescribeImages" 
            ], 
"Recurso": "*" 
        }, 
        { 
"Efeito": "Permitir", 
"Ação": [ 
"afirma: Descrever a Execução", 
"estados:DescreveEstadoMáquina", 
"afirma: IniciarExecução" 
            ], 
"Recurso": "*" 
        }, 
        { 
"Efeito": "Permitir", 
"Ação": [ 
"appconfig:StartDeployment", 
"appconfig:StopDeployment", 
"appconfig:GetDeployment" 
            ], 
"Recurso": "*" 
        }, 
        { 
"Efeito": "Permitir", 
"Ação": [ 
"logs:CreateLogGroup", 
"logs:CreateLogStream", 
"logs:PutLogEvents" 
            ], 
"Recurso": [ 
"arn:aws:logs:us-east-1:xxxx:log-group:/aws/codepipeline/eks-deploy-codepipeline", 
"arn:aws:logs:us-east-1:xxxxx:log-group:/aws/codepipeline/eks-deploy-codepipeline:log-stream:*" 
            ]
        }, 
        { 
"Sid": "EksClusterPolicy", 
"Efeito": "Permitir", 
"Ação": "eks:DescribeCluster", 
"Recurso": [ 
                "*" 
            ]
        }, 
        { 
"Sid": "EksVpcClusterPolicy", 
"Efeito": "Permitir", 
"Ação": [ 
"ec2:DescribeDhcpOptions", 
"ec2:DescribeNetworkInterfaces", 
"ec2:DescribeRouteTables", 
"ec2:DescribeSubnets", 
"ec2:DescribeSecurityGroups", 
"ec2:DescribeVpcs" 
            ], 
"Recurso": [ 
                "*" 
            ]
        }, 
        { 
"Efeito": "Permitir", 
"Ação": "ec2:CreateNetworkInterface", 
"Resource": "*", 
"Condição": { 
"StringEqualsIfExists": { 
"ec2:Subnet": [ 
"arn:aws:ec2:us-east-1:292170836962:exemplo-subrede/subrede1", 
"arn:aws:ec2:us-east-1:292170836962:subnet/subnet-example2" 
                    ]
                }
            }
        }, 
        { 
"Efeito": "Permitir", 
"Ação": "ec2:CreateNetworkInterfacePermission", 
"Resource": "*", 
"Condição": { 
"ArnEquals": { 
"ec2:Subnet": [ 
"arn:aws:ec2:us-east-1:xxxx:subnet/subnet-example1", 
"arn:aws:ec2:us-east-1:xxxx:subnet/subnet-example2" 
                    ]
                }
            }
        }, 
        { 
"Efeito": "Permitir", 
"Ação": "ec2:DeleteNetworkInterface", 
"Resource": "*", 
"Condição": { 
"StringEqualsIfExists": { 
"ec2:Subnet": [ 
"arn:aws:ec2:us-east-1:xxxxx:exemplo-subrede/subnet1", 
"arn:aws:ec2:us-east-1:xxxx:subnet/subnet-example2" 
                    ]
                }
            }
        }
    ], 
"Versão": "2012-10-17" 
}

 

  • Crie uma entrada de acesso no EKS cluster com AmazonEKSClusterAdminPolicy para a função de serviço codepipeline acima.

Execute o oleoduto

Caso quando o manifesto de kubectl for atualizado

codepipeline execution

 

(base) jatin.mehrotra@CK0662-001 codepipeline-eks-deployment-no-github % kubectl get pods
NOME E STATUS PRONTO REINICIA IDADE
hello-k8s-74fd98b69b-2pwrv 1/1 Rodando 0 2m37s
hello-k8s-74fd98b69b-g876f 1/1 Rodando 0 2m37s
hello-k8s-74fd98b69b-phs77 1/1 Correndo 0 2m37s

 

Caso quando o manifesto do mapa do leme for atualizado

codepipeline execution
(base) jatin.mehrotra@CK0662-001 codepipeline-eks-deployment-no-github % kubectl get pods
NOME E STATUS PRONTO REINICIA IDADE
teste-67cbfddc66-2gcvj 1/1 Correndo 0 10m

 

Do ponto de vista do desenvolvedor, DevOps

  • Com essa atualização, não preciso gerenciar projetos de codebuild ou qualquer tipo de ambiente de computação, nem gerenciar scripts complexos, permissões e instalações de ferramentas.
  • A seguir está a imagem da configuração que eu costumava ter com o codebuild antes desta atualização. Uma bagunça tão complexa.
before this update config
  • Isso certamente é um divisor de águas para desenvolvedores, engenheiros DevOps e engenheiros de infraestrutura que querem focar em problemas de negócios, suas aplicações e outras questões do Kubernetes como monitoramento e escalabilidade.

Essa não é uma abordagem GitOps, que é seguida pelo Flux/ArgoCD, mas sim a melhor abordagem DevOps para cluster EKS, na minha opinião.

Eu compartilho atualizações incríveis da AWS sobre DevOps, Kubernetes e GenAI diariamente em Linkedin, X. Me siga por lá para que eu possa facilitar sua vida.


Related Articles