DEV Community

Paulo Ponciano for AWS Community Builders

Posted on • Edited on • Originally published at Medium

IDP port e Crossplane composition no Amazon EKS [Lab Session]

Seguindo em mais um lab, este de certa forma é uma continuação do Serverless com Crossplane composition no EKS + GitOps [Lab Session]. Vamos adicionar mais alguns elementos, um deles é o Internal Developer Portal (IDP) port. O IDP nos permite abstrair muitos elementos subjacentes, proporcionando aos consumidores maior foco em suas entregas finais.

É claro, ainda é necessário manter esses 'elementos subjacentes' assim como a própria abstração dos mesmos. Esse normalmente é o trabalho do time de Engenharia de Plataforma.


Arquitetura do Lab

Arquitetura e combinação dos elementos do lab

Vamos utilizar a mesma composition do crossplane que entrega uma arquitetura serverless na AWS. Desta vez, o input das informações não será diretamente em um yaml de claim e sim no IDP port.

Com crossplane, o yaml utilizado para o claim já é bem enxuto; utilizando um IDP isso fica ainda mais simples para o consumidor.

Repositórios:

Port blueprints e actions

No DevPortal Builder do port, vamos criar os blueprints Cluster, Namespace e Order (stack serverless AWS). Blueprints são utilizados como modelos de dados dos nossos elementos e permitem a composição dos catálogos.

app.getport.io

Interface do app.getport.io com os blueprints

  • Os arquivos json utilizados estão em port/blueprints do repositório.

Cluster blueprint:

Blueprint Cluster no DevPortal Builder do port

{
  "identifier": "cluster",
  "description": "This blueprint represents a Kubernetes Cluster",
  "title": "Cluster",
  "icon": "Cluster",
  "schema": {
    "properties": {},
    "required": []
  },
  "mirrorProperties": {},
  "calculationProperties": {},
  "relations": {}
}
Enter fullscreen mode Exit fullscreen mode

Namespace blueprint:

Blueprint Namespace no DevPortal Builder do port

{
    "identifier": "namespace",
    "description": "This blueprint represents a k8s Namespace",
    "title": "Namespace",
    "icon": "Environment",
    "schema": {
      "properties": {
        "creationTimestamp": {
          "type": "string",
          "title": "Created",
          "format": "date-time",
          "description": "When the Namespace was created"
        },
        "labels": {
          "type": "object",
          "title": "Labels",
          "description": "Labels of the Namespace"
        }
      }
// Removed for brevity
Enter fullscreen mode Exit fullscreen mode

Order blueprint:

Blueprint Order no DevPortal Builder do port

{
  "identifier": "order",
  "description": "This blueprint represents an Order App",
  "title": "Order",
  "icon": "Microservice",
  "schema": {
    "properties": {
      "provider": {
        "icon": "AWS",
        "title": "Provider",
        "description": "The provider where the app is deployed",
        "type": "string",
        "default": "n/a",
        "enum": [
          "default",
          "n/a"
        ],
        "enumColors": {
          "default": "lightGray",
          "n/a": "lightGray"
        }
      }
// Removed for brevity
Enter fullscreen mode Exit fullscreen mode

Resultado:

Blueprints Cluster, Namespace e Order criados no port

  • Agora vamos criar as actions do blueprint Order. As actions serão responsáveis por acionar o GitHub Actions em eventos de CREATE e DELETE. Podemos editar o blueprint e inserir o json port/actions do repositório em 'Actions':

Edição do blueprint Order para inserir as actions

Este é o trecho em que informamos o workflow que será acionado em cada action:

// Removed for brevity
"invocationMethod": {
      "type": "GITHUB",
      "omitPayload": true,
      "omitUserInputs": false,
      "reportWorkflowStatus": true,
      "org": "paulofponciano",
      "repo": "EKS-Crossplane-ArgoCD",
      "workflow": "create-order-app.yaml"
    },
    "trigger": "CREATE",
    "description": "Create an Order App",
    "requiredApproval": false
  }
// Removed for brevity
Enter fullscreen mode Exit fullscreen mode

Na primeira integração, é necessário conectar o port ao GitHub para que ele possa acionar os workflows — GitHub app installation:

Instalação do GitHub App para conectar o port ao GitHub

Agora em Self-Service já temos as actions de Create e Delete para a composition do crossplane:

Actions de Create e Delete disponíveis no Self-Service do port

GitHub Actions

Os workflows do GitHub Actions serão responsáveis por receber os inputs enviados no payload do port quando as actions são executadas. Esses inputs são passados no manifesto de claim da composition do crossplane e é feito o commit desse manifesto em um repositório monitorado pelo ArgoCD (deployed_infra):

  • .github/workflows/create-order-app.yaml
name: Create an order app
on:
  workflow_dispatch:
    inputs:
      name:
        required: true
        description: "The name of the app"
      provider:
        required: true
        description: "The provider where the app is deployed"
        default: "aws"
      region:
        required: true
        description: "The provider region"
        default: "us-east-1"
      ownerName:
        required: true
        description: "The owner name"
        default: "ownerName"
      projectName:
        required: true
        description: "The project name"
        default: "projectName"
jobs:
  deploy-app:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          persist-credentials: false
          fetch-depth: 0

      - name: Create an order app
        run: |
          chmod +x scripts/create-app-order.sh
          ./scripts/create-app-order.sh ${{ inputs.name }} ${{ inputs.provider }} ${{ inputs.region }} ${{ inputs.ownerName }} ${{ inputs.projectName }}

      - name: Commit changes
        run: |
          git config --local user.email "github-actions[bot]@users.noreply.github.com"
          git config --local user.name "github-actions[bot]"
          git add .
          git commit -a -m "Create app order ${{ inputs.name }}"

      - name: push
        uses: ad-m/github-push-action@master
Enter fullscreen mode Exit fullscreen mode
  • scripts/create-app-order.sh
NAME=$1
PROVIDER=$2
REGION=$3
OWNER=$4
PROJECT=$5

FILE_PATH=deployed_infra/${NAME}.yaml

cp crossplane_compositions/order/order-claim-port.yaml $FILE_PATH
yq --inplace ".metadata.name = \"${NAME}\"" $FILE_PATH
yq --inplace ".spec.resourceConfig.providerConfigName = \"${PROVIDER}\"" $FILE_PATH
yq --inplace ".spec.resourceConfig.region = \"${REGION}\"" $FILE_PATH
yq --inplace ".spec.resourceConfig.tags.ownerName = \"${OWNER}\"" $FILE_PATH
yq --inplace ".spec.resourceConfig.tags.projectName = \"${PROJECT}\"" $FILE_PATH
Enter fullscreen mode Exit fullscreen mode
  • .github/workflows/delete-order-app.yaml
name: Delete an order app
on:
  workflow_dispatch:
    inputs:
      name:
        required: true
        description: "The name of the app"
jobs:
  delete-app:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          persist-credentials: false
          fetch-depth: 0

      - name: Delete an order app
        run: |
          rm deployed_infra/${{ inputs.name }}.yaml

      - name: Commit changes
        run: |
          git config --local user.email "github-actions[bot]@users.noreply.github.com"
          git config --local user.name "github-actions[bot]"
          git add .
          git commit -a -m "Delete app order ${{ inputs.name }}"

      - name: push
        uses: ad-m/github-push-action@master
Enter fullscreen mode Exit fullscreen mode

ArgoCD

Criamos uma application no ArgoCD, definindo como source o repo/path onde teremos o commit do manifesto feito pelo workflow do GitHub Actions:

apiVersion: v1
kind: Secret
metadata:
  name: public-repo-crossplane
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: repository
stringData:
  type: git
  url: https://github.com/paulofponciano/EKS-Crossplane-ArgoCD.git
---
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: idp
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  description: Internal Developer Portal
  sourceRepos:
    - 'https://github.com/paulofponciano/EKS-Crossplane-ArgoCD.git'
  destinations:
    - namespace: '*'
      server: 'https://kubernetes.default.svc'
      name: 'in-cluster'
  clusterResourceWhitelist:
    - group: '*'
      kind: '*'
  namespaceResourceWhitelist:
    - group: '*'
      kind: '*'
  orphanedResources:
    warn: true
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: idp-infra-aws
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: idp
  source:
    repoURL: https://github.com/paulofponciano/EKS-Crossplane-ArgoCD.git
    targetRevision: HEAD
    path: deployed_infra
  destination:
    server: https://kubernetes.default.svc
  syncPolicy:
    automated:
      selfHeal: true
      prune: true
      allowEmpty: true
Enter fullscreen mode Exit fullscreen mode
kubectl apply -f argocd/application.yaml
Enter fullscreen mode Exit fullscreen mode

Application idp-infra-aws criada no ArgoCD

Port k8s-exporter

O k8s-exporter permite que o port possa ingerir de volta os dados dos recursos criados pelo crossplane no cluster kubernetes, assim podendo alimentar o catálogo do IDP.

Port Documentation - Kubernetes

  • Precisamos das credenciais de API do port para instalação via helm no cluster. Essas credenciais já existem no port, vamos apenas utilizá-las como variáveis na instalação:

Credenciais de API do port (Client ID e Client Secret)

  • Antes de executar a instalação via helm, precisamos informar no arquivo config.yaml os atributos para que os recursos criados sejam 'reconhecidos' como entidades, assim serão exportados para o port:
# Removed for brevity
- kind: api.pauloponciano.pro/v1alpha1/customorder
  selector:
    query: .metadata.namespace | startswith("environment")
  port:
    entity:
      mappings:
        - identifier: .metadata.name + "-" + .metadata.namespace + "-" + "paulop"
          title: .metadata.name
          icon: '"Microservices"'
          blueprint: '"order"'
          properties:
            provider: .spec.resourceConfig.providerConfigName
            region: .spec.resourceConfig.region
            ownerName: .spec.resourceConfig.tags.ownerName
            projectName: .spec.resourceConfig.tags.projectName
            labels: .metadata.labels
            annotations: .metadata.annotations
          relations:
            Namespace: .metadata.namespace + "-" + "paulop"
Enter fullscreen mode Exit fullscreen mode
  • Instalação:
helm repo add port-labs https://port-labs.github.io/helm-charts

helm upgrade --install port-k8s-exporter port-labs/port-k8s-exporter \
    --create-namespace --namespace port-k8s-exporter \
    --set secret.secrets.portClientId=$CLIENT_ID --set secret.secrets.portClientSecret=$CLIENT_SECRET \
    --set-file configMap.config=config.yaml
Enter fullscreen mode Exit fullscreen mode

Instalação do port-k8s-exporter via helm

Agora já podemos verificar o que está sendo ingerido e apresentado no catálogo do port:

Catálogo do port com os Clusters ingeridos

Catálogo do port com os Namespaces ingeridos

Catálogo do port com a aba Orders ainda vazia

Não temos nada em Orders porque ainda não criamos uma, calma jovem! Faremos isso da mesma forma que o usuário fará.

Usando o Self-Service

  • CREATE

Na área de self-service do port, vamos executar a action de CREATE, fazendo os inputs necessários para o claim da composition do crossplane:

Formulário de inputs da action de CREATE no port

Sucesso da execução da action:

Action de CREATE executada com sucesso no port

Sucesso na execução do workflow de create no GitHub Actions:

Workflow de create concluído com sucesso no GitHub Actions

O manifesto de claim foi criado com os inputs feitos através do IDP:

Manifesto de claim gerado a partir dos inputs do IDP

O ArgoCD fez a entrega do claim no cluster kubernetes que já possui a composition e definition do crossplane, assim os recursos da stack são criados na AWS:

ArgoCD sincronizando o claim e criando os recursos da stack

Voltando ao catálogo do port, em Orders:

Aba Orders do catálogo do port com a nova entidade

Detalhes da Order criada no catálogo do port

AWS stack serverless:

Recursos da stack serverless criados na console AWS

Detalhe dos recursos serverless na AWS

Confirmação da stack serverless em execução na AWS

  • DELETE

Vamos agora executar a action de DELETE, também pelo IDP:

Execução da action de DELETE pelo IDP port

Workflow de delete:

Workflow de delete executado no GitHub Actions

ArgoCD prune resources:

ArgoCD removendo os recursos com prune após o delete

Happy building!

References:

Top comments (0)