Orchestration

Build Your Self-Service Dev Portal

July 3, 2026 Kubezilla Team 11 min read

Introduction

In today’s fast-paced development landscape, empowering developers with self-service capabilities is no longer a luxury but a necessity. As organizations scale their microservices architectures on Kubernetes, the complexity of managing environments, deploying applications, and understanding the sprawling ecosystem of services can quickly become overwhelming. Developers often find themselves navigating a labyrinth of internal tools, documentation, and tribal knowledge, leading to inefficiencies, increased cognitive load, and slower innovation cycles.

Enter the Developer Portal: a centralized, intuitive interface designed to streamline the developer experience. A well-implemented developer portal provides a single pane of glass for everything from discovering existing services and their APIs to provisioning new environments, deploying code, and accessing relevant documentation. By abstracting away the underlying infrastructure complexities and offering curated pathways, developer portals significantly reduce friction, allowing engineers to focus on what they do best: writing code and delivering value. This guide will walk you through building your own self-service developer portal using Port, a powerful platform designed to unify your development ecosystem.

Port acts as the central nervous system for your development operations, integrating with your existing tools and providing a customizable Developer Catalog. It allows you to define your software components, their relationships, and lifecycle events, enabling developers to discover, interact with, and even provision resources directly from a user-friendly interface. By leveraging Port, you can transform your Kubernetes clusters from an operational burden into a true self-service platform, accelerating development velocity and fostering a culture of autonomy and efficiency.

TL;DR: Building a Self-Service Developer Portal with Port

Empower your developers with a self-service portal using Port. Define your software catalog, integrate with Git and Kubernetes, and enable self-service actions. This guide covers setting up Port, defining blueprints, registering entities, and creating self-service actions to deploy applications or provision infrastructure directly from the portal.

Key Commands:


# Install Port's CLI
npm install -g @port-labs/port-cli

# Login to Port
port login

# Initialize a blueprint (example)
port bp init --identifier microservice --title "Microservice" --schema-file microservice.json

# Register an entity
port entity create --blueprint microservice --identifier my-app --title "My Application" --properties '{"repoUrl": "https://github.com/my-org/my-app"}'

# Trigger a self-service action
# Go to Port UI -> Select Catalog Item -> Click "Actions" -> Trigger Action
    

Prerequisites

Before diving into building your self-service developer portal with Port, ensure you have the following:

  • Kubernetes Cluster: An existing Kubernetes cluster (e.g., Minikube, GKE, EKS, AKS) where you can deploy applications. We’ll be using it to demonstrate self-service deployments. For efficient node management, consider exploring Karpenter Cost Optimization.
  • kubectl: The Kubernetes command-line tool, configured to connect to your cluster. Refer to the official Kubernetes documentation for installation.
  • Helm: The Kubernetes package manager. Installation instructions can be found on the Helm website.
  • Port Account: A free or paid Port account. You can sign up at port.io.
  • Node.js and npm: Required for installing the Port CLI. Download from nodejs.org.
  • Git: For cloning repositories and managing code.
  • Basic understanding of CI/CD: Familiarity with concepts like GitHub Actions, GitLab CI, or Jenkins will be beneficial for setting up self-service actions.

Step-by-Step Guide

Step 1: Install and Configure Port CLI

The Port CLI is your primary tool for interacting with the Port API, allowing you to define blueprints, register entities, and manage your developer catalog programmatically. This is crucial for automating the population of your portal and integrating it into your existing CI/CD pipelines.

First, install the Port CLI globally using npm. Once installed, you’ll need to log in to your Port account through the CLI. This process will open your web browser for authentication, linking your CLI session to your Port workspace. After successful authentication, your CLI is ready to interact with your Port instance.


# Install the Port CLI globally
npm install -g @port-labs/port-cli

# Verify installation
port --version

# Login to your Port account. This will open a browser for authentication.
port login

Verify:

After running port login, your browser should open to the Port authentication page. Once authenticated, the CLI will confirm your login.


# Example successful login output
info: Opening browser to your Port login page...
info: Successfully logged in to Port!

Step 2: Define Blueprints in Port

Blueprints are the schema for your software catalog. They define the types of entities (e.g., services, environments, deployments, teams) that will be represented in your developer portal and the properties associated with them. Think of them as custom resource definitions (CRDs) for your software components. For instance, a “Microservice” blueprint might have properties like repoUrl, owner, tier, and documentationUrl. Defining clear and comprehensive blueprints is the foundation of a useful and organized portal.

We’ll start by defining a simple Microservice blueprint. This blueprint will describe the common attributes of a microservice in your organization. We’ll save the schema to a JSON file and then upload it to Port using the CLI.


# microservice.json
{
  "identifier": "microservice",
  "title": "Microservice",
  "icon": "Microservice",
  "properties": {
    "repoUrl": {
      "type": "string",
      "title": "Repository URL",
      "format": "url"
    },
    "owner": {
      "type": "string",
      "title": "Owner Team",
      "blueprint": "team",
      "icon": "Team"
    },
    "tier": {
      "type": "string",
      "title": "Service Tier",
      "enum": ["1", "2", "3"],
      "default": "2"
    },
    "documentationUrl": {
      "type": "string",
      "title": "Documentation URL",
      "format": "url"
    }
  },
  "relations": {
    "runsOnEnvironment": {
      "target": "environment",
      "title": "Runs On Environment",
      "many": true
    }
  }
}

# Create the blueprint file
touch microservice.json
# Paste the above JSON content into microservice.json

# Upload the blueprint to Port
port bp init --identifier microservice --title "Microservice" --schema-file microservice.json

Verify:

You should see a confirmation message from the CLI. You can also log into the Port UI, navigate to “Settings” -> “Blueprints”, and confirm that your “Microservice” blueprint has been created with the specified properties.


# Example successful blueprint creation output
info: Blueprint "microservice" created successfully!

Step 3: Register Entities in Port

Entities are instances of your blueprints. They represent the actual software components, environments, or teams that exist in your ecosystem. Registering entities populates your developer catalog, making your services discoverable and manageable. This can be done manually via the UI, programmatically via the CLI, or automatically via integrations.

We’ll register a sample microservice and a team to demonstrate. Notice how the owner property in the microservice entity refers to the team blueprint, establishing a relationship within your catalog.


# First, create a 'team' blueprint (if you haven't already, for the relation to work)
# team.json
# {
#   "identifier": "team",
#   "title": "Team",
#   "properties": {
#     "lead": { "type": "string", "title": "Team Lead" },
#     "slackChannel": { "type": "string", "title": "Slack Channel" }
#   }
# }
# port bp init --identifier team --title "Team" --schema-file team.json

# Register a Team entity
port entity create --blueprint team --identifier dev-team-a --title "Development Team A" --properties '{"lead": "Alice Smith", "slackChannel": "#dev-team-a"}'

# Register a Microservice entity
port entity create --blueprint microservice --identifier my-first-service --title "My First Service" --properties '{"repoUrl": "https://github.com/my-org/my-first-service", "owner": "dev-team-a", "tier": "2", "documentationUrl": "https://docs.my-org.com/my-first-service"}'

Verify:

Check the Port UI. Navigate to the “Catalog” section. You should now see “My First Service” listed under the “Microservice” blueprint and “Development Team A” under the “Team” blueprint. Clicking on “My First Service” should display all the properties you defined, including the linked owner team.


# Example successful entity creation output
info: Entity "dev-team-a" created successfully for blueprint "team"!
info: Entity "my-first-service" created successfully for blueprint "microservice"!

Step 4: Create Self-Service Actions

Self-service actions are the core of a developer portal. They allow developers to trigger predefined workflows directly from the Port UI without needing to access underlying infrastructure or specialized tools. These actions can range from deploying a new service, provisioning a database, requesting environment access, or even creating a new GitHub repository. Port integrates with various CI/CD tools (e.g., GitHub Actions, GitLab CI, Jenkins, Argo CD) to execute these workflows.

For this example, we’ll create a simple GitHub Actions workflow that simulates deploying a new Kubernetes manifest. We’ll then configure a Port action that triggers this workflow. This demonstrates how Port can orchestrate actions in your existing CI/CD system. For more advanced Kubernetes deployments, consider integrating with tools like Argo CD or Flux.

4.1: Create a GitHub Actions Workflow

First, create a simple GitHub Actions workflow file in a repository. This workflow will be triggered by Port. Let’s assume you have a repository named self-service-actions.


# .github/workflows/deploy-app.yaml
name: Deploy Application via Port

on:
  workflow_dispatch:
    inputs:
      serviceName:
        description: 'Name of the service to deploy'
        required: true
        type: string
      namespace:
        description: 'Kubernetes Namespace'
        required: true
        default: 'default'
        type: string
      image:
        description: 'Docker image to deploy (e.g., nginx:latest)'
        required: true
        type: string
      replicas:
        description: 'Number of replicas'
        required: true
        default: '1'
        type: number

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Setup Kubeconfig (example - in a real scenario, use OIDC or secrets)
        run: |
          echo "${{ secrets.KUBECONFIG_BASE64 }}" | base64 -d > ~/.kube/config
          chmod 600 ~/.kube/config
        env:
          KUBECONFIG_BASE64: ${{ secrets.KUBECONFIG_BASE64 }}

      - name: Deploy to Kubernetes
        run: |
          cat <

Important Security Note: Storing KUBECONFIG_BASE64 as a GitHub secret is a simplified example. In a production environment, you should use more secure methods like OpenID Connect (OIDC) with your cloud provider or a dedicated service account with granular permissions for your Kubernetes deployments. For enhanced security, also consider Kubernetes Network Policies Security Guide.

4.2: Define the Action in Port

Now, create an action in Port that triggers this GitHub Actions workflow. This action will be associated with the Microservice blueprint, allowing developers to deploy new services directly from the catalog.


# deploy-action.json
{
  "identifier": "deployNewService",
  "title": "Deploy New Service",
  "icon": "Deploy",
  "description": "Deploys a new Kubernetes service from a Docker image.",
  "blueprint": "microservice",
  "trigger": "github-actions",
  "url": "https://github.com/my-org/self-service-actions/actions/workflows/deploy-app.yaml",
  "payload": {
    "properties": {
      "serviceName": {
        "type": "string",
        "title": "Service Name",
        "icon": "Name"
      },
      "namespace": {
        "type": "string",
        "title": "Kubernetes Namespace",
        "default": "default"
      },
      "image": {
        "type": "string",
        "title": "Docker Image",
        "default": "nginx:latest"
      },
      "replicas": {
        "type": "number",
        "title": "Number of Replicas",
        "default": 1
      }
    },
    "required": ["serviceName", "image"]
  }
}

# Create the action file
touch deploy-action.json
# Paste the above JSON content into deploy-action.json

# Upload the action to Port
port action init --identifier deployNewService --title "Deploy New Service" --blueprint microservice --schema-file deploy-action.json

Verify:

Log into the Port UI. Navigate to "Settings" -> "Actions". You should see "Deploy New Service" listed. More importantly, go to the "Catalog" and select any entity under the "Microservice" blueprint. You should now see an "Actions" button or tab, and clicking it will reveal the "Deploy New Service" action. When you click it, a form will appear with the input fields defined in your payload.properties. Filling out the form and clicking "Run" will trigger the GitHub Actions workflow.


# Example successful action creation output
info: Action "deployNewService" created successfully for blueprint "microservice"!

Step 5: Integrate with Your CI/CD and GitOps

For a truly dynamic developer portal, you need to keep your Port catalog in sync with your actual infrastructure and code. This typically involves integrating Port with your CI/CD pipelines and GitOps workflows. Whenever a new service is deployed, an environment is provisioned, or a repository is created, Port should be updated automatically.

You can use the Port CLI or API within your CI/CD pipelines to register or update entities. For example, after a successful deployment of a new microservice, your CI/CD job can call port entity create or port entity update to reflect the new service in the catalog. Similarly, for GitOps, you can leverage Port's GitOps Exporter to manage Port entities as code in your Git repository.

Here's an example of how you might update a microservice entity in Port after a successful CI/CD deployment in a GitHub Actions workflow:


# .github/workflows/update-port-entity.yaml (part of your existing deploy workflow)
name: Update Port Entity after Deployment

on:
  push:
    branches:
      - main
    paths:
      - 'services/**' # Trigger when service code changes

jobs:
  deploy-and-update-port:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      # ... (Your existing build and deploy steps here) ...
      # For example, deploying a service via kubectl or Helm

      - name: Install Port CLI
        run: npm install -g @port-labs/port-cli

      - name: Login to Port
        run: port login --client-id ${{ secrets.PORT_CLIENT_ID }} --client-secret ${{ secrets.PORT_CLIENT_SECRET }}

      - name: Update Microservice Entity in Port
        run: |
          SERVICE_NAME="my-first-service" # Get this dynamically from your build system
          NEW_VERSION="1.0.${{ github.run_number }}"
          # Assuming you have a property 'version' in your microservice blueprint
          port entity update \
            --blueprint microservice \
            --identifier $SERVICE_NAME \
            --properties "{\"version\": \"${NEW_VERSION}\", \"lastDeployedAt\": \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\"}"
        env:
          PORT_CLIENT_ID: ${{ secrets.PORT_CLIENT_ID }}
          PORT_CLIENT_SECRET: ${{ secrets.PORT_CLIENT_SECRET }}

Verify:

After a successful run of your CI/CD pipeline (e.g., pushing a commit that triggers the above workflow), log into the Port UI. Navigate to the "Catalog" and select the updated microservice entity (e.g., "My First Service"). You should see its properties (like version or lastDeployedAt) updated to reflect the latest deployment information.


# Example successful entity update output
info: Entity "my-first-service" updated successfully for blueprint "microservice"!

Production Considerations

Deploying a developer portal in production requires more than just setting up blueprints and actions. Here are critical considerations:

  1. Security and Access Control:
    • Authentication & Authorization: Integrate Port with your organization's SSO (e.g., Okta, Auth0, Azure AD) for seamless and secure access. Configure granular RBAC within Port to ensure developers only have access to the actions and entities relevant to their roles and teams.
    • Secrets Management: Ensure that any secrets used by your CI/CD workflows (e.g., Kubernetes API tokens, cloud credentials, Port API tokens) are managed securely using dedicated secrets management solutions (e.g., HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, Google Secret Manager) and never hardcoded.
    • Least Privilege: Ensure that the service accounts or identities used by your CI/CD pipelines to interact with Kubernetes or other cloud resources adhere strictly to the principle of least privilege. For Kubernetes, this means using specific RBAC roles.
  2. Observability and Monitoring:
    • Action Auditing: Port provides an audit log of all actions triggered. Monitor these logs to track who performed what action and when. Integrate these logs with your central SIEM or logging platform.
    • Workflow Monitoring: Monitor the underlying CI/CD workflows (GitHub Actions, Jenkins jobs, etc.) that Port triggers. Set up alerts for failures, long-running jobs, or unusual activity. For Kubernetes-native observability, consider eBPF Observability with Hubble.
    • Port Health: Monitor the health and performance of your Port instance itself (if self-hosted) or rely on Port's SaaS reliability.
  3. Scalability and Performance:
    • CI/CD Runner Scale: Ensure your CI/CD runners (e.g., GitHub Actions self-hosted runners, Jenkins agents) can scale to handle the expected load of self-service actions.
    • API Rate Limits: Be mindful of API rate limits for Port and any integrated third-party services (GitHub, cloud providers) when automating entity registration or updates. Implement exponential backoff for retries.
  4. Documentation and Onboarding:
    • Comprehensive Documentation: Provide clear and concise documentation for your developer portal, explaining how to use it, what actions are available, and what each blueprint represents.
    • Onboarding Workflows: Integrate Port into your developer onboarding process. New hires should be guided on how to use the portal to discover services, provision environments, and deploy their first application.
  5. GitOps and Automation:
    • Port as Code: Manage your Port blueprints, actions, and even initial entities as code within your Git repositories. This aligns with GitOps principles, allowing for version control, peer review, and automated deployment of your portal's configuration. Port's declarative API supports this.
    • Automated Entity Sync: Implement automated processes (e.g., daily cron jobs, CI/CD hooks) to synchronize entities from your source of truth (e.g., Kubernetes cluster, cloud accounts, Git repositories) into Port. This ensures your catalog is always up-to-date.
  6. Cost Management:
    • Resource Tagging: If self-service actions provision cloud resources, ensure they are properly tagged for cost allocation and tracking.
    • Automated Cleanup: Implement actions for automated cleanup or de-provisioning of temporary environments or resources to avoid unnecessary cloud costs. Tools like Karpenter Cost Optimization can be helpful for Kubernetes node management.

Troubleshooting

1. Port CLI Login Issues

Issue: The port login command fails or doesn't open a browser, or authentication fails in the browser.

Solution:

  • Check Network Connectivity: Ensure your machine has internet access and can reach port.io.
  • Browser Pop-up Blockers: Disable any browser pop-up blockers that might prevent the authentication window from opening.
  • CLI Version: Ensure you have the latest version of the Port CLI. Update with npm install -g @port-labs/port-cli.
  • Manual Token Login: If automatic browser login fails, you can generate a client ID and secret from your Port workspace settings (Settings -> API Tokens) and log in manually:
    
    port login --client-id <YOUR_CLIENT_ID> --client-secret <YOUR_CLIENT_SECRET>
    

2. Blueprint/Entity Creation Errors

Issue: port bp init or port entity create commands fail with schema validation errors or permission issues.

Solution:

  • JSON Schema Validation: Double-check your JSON files for syntax errors. Use an online JSON validator to ensure they are well-formed. Pay close attention to commas, brackets, and quotes.
  • Identifier Uniqueness: Ensure blueprint and entity identifiers are unique within their respective types and blueprints.
  • Permissions: The Port user or API token used by the CLI must have sufficient permissions to create/update blueprints and entities in your workspace. Check your Port workspace roles.
  • Blueprint Existence: If an entity references a blueprint (e.g., "blueprint": "team"), ensure that blueprint already exists in Port.

3. Self-Service Action Not Appearing in UI

Issue: You've created an action with port action init, but it doesn't show up on entities in the Port UI.

Solution:

  • Blueprint Association: Ensure the action's blueprint property correctly matches the identifier of the blueprint you want to associate it with (e.g., "blueprint": "microservice").
  • Identifier Uniqueness: Action identifiers must be unique within a blueprint.
  • Refresh UI: Sometimes a hard refresh of the Port UI (Ctrl+F5 or Cmd+Shift+R) is needed to load new configurations.
  • Check Action Status: In the Port UI, go to "Settings" -> "Actions" and verify that the action is listed and enabled.

4. GitHub Actions Workflow Not Triggering

Issue: You trigger a self-service action in Port, but the associated GitHub Actions workflow doesn't run.

Solution:

  • GitHub App Installation: Ensure the Port GitHub App is correctly installed in your GitHub organization/repository and has the necessary permissions (especially for workflow_dispatch). Check Port's GitHub Actions integration guide.
  • Workflow Dispatch Event: Verify that your GitHub Actions workflow is correctly configured to respond to workflow_dispatch events, as shown in the example:
    
    on:
      workflow_dispatch:
        inputs:
          # ...
    
  • Repository URL: The url in your Port action definition must point to the correct GitHub workflow file path: https://github.com/<ORG>/<REPO>/actions/workflows/<WORKFLOW_FILE>.yaml.
  • GitHub Token: Ensure the GitHub App has a valid token and is correctly configured in Port to make API calls to GitHub.
  • GitHub Logs: Check the "Actions" tab in your GitHub repository for any failed workflow runs or errors related to triggering.

5. Kubernetes Deployment Failures from GitHub Actions

Issue: The GitHub Actions workflow triggers, but the Kubernetes deployment steps fail.

Solution:

  • Kubeconfig Validity: Verify that the KUBECONFIG_BASE64 secret used in your GitHub Actions workflow is correctly base64 encoded and points to a valid Kubernetes cluster configuration. Test it locally.
  • RBAC Permissions: Ensure the Kubernetes user/service account associated with the Kubeconfig has sufficient RBAC permissions to create/update Deployments and Services in the target namespace.
  • Namespace Existence: Confirm that the target Kubernetes namespace exists. If not, the deployment will fail. You might need to add a step to create the namespace if it doesn't exist.
  • Image Pull Issues: Check if the Docker image specified (e.g., nginx:latest) can be pulled from the cluster. Ensure proper registry authentication if using private registries.
  • kubectl Version: Ensure the kubectl version used in the GitHub Actions runner is compatible with your Kubernetes cluster.

6. Port UI Performance Issues

Issue: The Port UI is slow or unresponsive, especially with many entities.

Solution:

  • Browser Cache: Clear your browser cache and cookies.
  • Network Latency: Check your internet connection.
  • Too Many Entities: If you have tens of thousands of entities, ensure your blueprints are optimized. Consider using filters and views in Port to manage the display of entities.
  • Port Support: If the issue persists, especially for a SaaS instance, contact Port support for assistance.

7. Data Inconsistencies (Port vs. Reality)

Issue: The information in Port doesn't match the actual state of your infrastructure or services.

Solution:

  • Automated Sync: Implement automated mechanisms (CI/CD jobs, webhooks, cron jobs) to regularly update entities in Port from your sources of truth (e.g., Git repositories, Kubernetes API, cloud APIs).
  • Webhooks: Leverage webhooks from your Git providers or CI/CD systems to trigger Port API calls whenever relevant changes occur.
  • Port Integrations: Explore Port's native integrations (e.g., Kubernetes Ingester, Cloud Integrations) to automatically discover and sync resources. For instance, the Kubernetes Ingester can directly populate your catalog with Kubernetes resources.
  • Manual Verification: Periodically review critical entities manually to spot discrepancies.

FAQ Section

Q1: What is a Developer Portal and why do I need one?

A Developer Portal is a centralized platform that provides developers with a single pane of glass to discover services, access documentation, manage environments, and trigger self-service actions. You need one to reduce cognitive load, accelerate development cycles, enhance collaboration, improve service discoverability, and empower developers by abstracting away infrastructure complexities.

Q2: How does Port integrate with my existing CI/CD pipelines?

Port integrates with CI/CD tools (like GitHub Actions, GitLab CI, Jenkins, Argo Workflows) by acting as an orchestration layer. When a developer triggers an action in Port, Port sends a trigger (e.g., a workflow_dispatch event for GitHub Actions, a webhook for Jenkins) to your CI/CD system. The CI/CD pipeline then executes the predefined workflow, which can interact with your Kubernetes cluster, cloud providers, or any other tooling. Additionally, your CI/CD pipelines can use the Port CLI or API to update entities in the catalog after successful builds or deployments.

Q3: Can Port help with Kubernetes resource management?

Absolutely. Port can define blueprints for Kubernetes resources (Deployments, Services, Ingresses, Namespaces) and allow developers to provision, update, or delete them through self-service actions. For example, a developer could trigger an action to "Create New Namespace" or "Deploy Service to Staging." Port can also integrate with Kubernetes resource ingesters (like its own Kubernetes Ingester) to automatically populate your catalog with existing Kubernetes resources, providing a comprehensive view of your cluster's state. For managing network traffic, consider our Kubernetes Gateway API vs Ingress: The Complete Migration Guide.

Q4: Is Port specific to Kubernetes, or can it manage other resources?

Port is infrastructure-agnostic. While it's incredibly powerful for managing Kubernetes-based microservices, it can define blueprints and actions for virtually any resource. This includes cloud resources (AWS S3 buckets, GCP projects, Azure functions), internal APIs, documentation sites, teams, environments, and even physical devices. It aims to be a single source of truth for your entire software ecosystem, encompassing both infrastructure and applications.

Q5: How can I ensure the data in my Port catalog is always up-to-date?

Maintaining data freshness is crucial. You can achieve this through several methods:

  • CI/CD Integration: Update Port entities

Leave a comment