Setting up an internal developer portal with Port, Terraform and Codefresh: a three part demo

Dec 18, 2023

Setting up an internal developer portal with Port, Terraform and Codefresh: a three part demo
Kostis Kapelonis

Kostis Kapelonis

Kostis Kapelonis

Kostis Kapelonis

Home
Blog
Setting up an internal developer portal with Port, Terraform and Codefresh: a three part demo

Using an Internal Developer Portal is quickly becoming a tool of choice to provide an interface for developers as part of a broader platform engineering initiative. With a Portal, developers can use self-service to build, deploy and manage applications, in a single click. But how do you build the portal? 

This post will take you through a three part demo, using CodeFresh, Terraform and Port. 

  • The first part shows how to create the data model for the portal. 
  • The second part dives deeper into how to create self-service actions for developers.
  • Finally, the third part presents how developers can use Port to easily create a microservice, using portal-as-code. 

Hopefully, after reading this blog post, you’ll have a strong understanding of how an Internal Developer Portal works and what you can do with it. 

This blog post is based on a webinar we held with Kostis Kapelonis from CodeFresh, the GitOps Enterprise platform (also available as a recording). All the resource files used are public at  https://github.com/kostis-codefresh/port-demo

What is an Internal Developer Portal?

An Internal Developer Portal is a central organizational platform that provides developers with the ability to access all the tools and information they need for building, deploying, and managing applications, in a self-service manner and in a simplified way. This could include container registries, vulnerability scanners, CI tools, IaC tools, control planes, information on how microservices are connected, and more.

One of the key points in using a portal is that it abstracts away complexities and shows developers only the information they need. For example, scaffolding a microservice can be done in a single click, because an Internal Developer Portal abstracts everything away while still setting guardrails that will ensure developers adhere to engineering standards.

As such, an Internal Developer Portal is the solution for reducing the cognitive load on developers. This helps streamline the development process and foster efficiency and innovation.

There are several use cases a developer portal can handle. Each organization can customize their portal according to their needs and priorities. Some examples that we have seen in our customers are:

  • Microservice catalog
  • Cloud resource catalog
  • Kubernetes and ArgoCD visibility
  • Cloud resource permissions
  • Ephemeral environments
  • IaC for developers
  • Package management
  • On-call and incident management

It is therefore very important before adopting a portal to decide what are your priorities and limitations.

Part #1: Creating a Model That Matches Your Engineering DNA

To take you through the process of setting up the portal, we’ll begin with the data model. To illustrate our points, we’ll use a fun example of how to use Port to manage your music collection. This is a contrived example, but it will give you a very good idea about the flexibility of Port.

In Port, the first step is to create a blueprint. Blueprints are the portal’s building blocks, driving the software catalog and its entities, as well as scorecards and self-service actions. In this example, we’ll focus on the creation of the software catalog. 

To define a blueprint, you can either:

  • Use Port’s UI
  • Use Port’s API from your favorite programming language
  • Use an IAC tools such as terraform or Pulumi

In our example we are using Terrraform. If you “apply” those files with the terraform CLI you will see the following in your Port Dashboard.

In this case, we created three blueprints: one for “Song”, one for “Album” and one for “Artist”. If you are a developer you can think of blueprints as classes; if you are a database person you can think of them like table definitions. For each blueprint you define a list of properties they contain (such as the name of the artist and their genre).

The next step is to define relationships, i.e the dependencies, between the blueprints. In this case, defining that the song belongs to an album and the album belongs to an artist. 

Once we ingest the data, the blueprints will put it in the software catalog, like this: 

By clicking on any entity you can see all of its relationships. For example, you can look for a specific album and see who the artist is and which songs it contains, you can go to the artist and see which albums they are related to, etc.

Relationships can be followed in both directions. You can easily find which artist has published which albums as well as which songs belong to an album.

Now take this example and try to draw an analogy as to what we mean when we talk about building a “data model” in Port. Port can be used to map your cloud infrastructure and the relationship between its various components. Instead of “a song is “part of” an album” - “a running service is “deployed at” a Kubernetes cluster. 

Part #2: Creating a Port Blueprint Just for Developers

The song/album/artist terraform blueprint is great if you want to understand how designing a schema works. Let’s look at a more realistic example 

We will create a portal specifically for developers and help them see everything they need for their day-to-day job in a single dashboard. The end result would also be to offer them self-service capabilities when they need to scaffold a new microservice. 

We’ll begin by defining the following blueprints:

  • An “environment” blueprint. In our case, it’s Kubernetes, but the developer doesn’t need to know this.
  • A microservice blueprint that represents an application
  • A Library blueprint that will explain which libraries/frameworks are used in the application
  • A Deployment which connects applications with environments
  • A “Build” blueprint -  this is the typical Continuous Integration build which creates the initial Docker image.; and a
  • A promotion blueprint - so you can see which microservice was promoted from which environment.

It is important to explain that Port entities can be anything you want and you don’t always have to map them to real entities. For example, an “environment” is a Kubernetes cluster. But the “promotion” blueprint just records that a promotion happened between two environments.

The next step is to define the relations between the blueprints. This will help us understand, once the portal is populated with data, which specific deployment is tied to which specific microservice and environment. You can see all the details again in Terraform at https://github.com/kostis-codefresh/port-demo/tree/main/developer-demo 

This is the minimum developers should see for this particular example. Everything else is not interesting or relevant to them. Notice that we don’t really say that environments are actually powered by Kubernetes.

With the blueprints out of the way, how can developers use them effectively? 

Part #3: Creating Everything a Developer Needs with a Single Click

Now it’s time to show how developers can replace the lengthy process that usually takes place when they build a new application with a single step in Port.

Imagine the scenario where a developer wants to create a brand new application (or microservice).

Usually, the process includes the following steps:

  1. Creating a Git repo
  2. Committing initial files
  3. Creating a Continuous integration pipeline to build the code
  4. Committing the pipeline 
  5. Create a Kubernetes cluster
  6. Creating a deployment pipeline
  7. Building the application
  8. Making the first deployment and all deployments there after.

In many cases, to complete these tasks, the developer will need to ask for resources and service from different people and even other departments. In a big company a developer might have to:

  • Go first to the GitHub team and ask for the repository
  • Go to the Kubernetes team and ask for a cluster
  • Go the CI team and ask for a pipeline
  • And so on

With Port, we will give the power to developers to take care of all this in a single step. And it will be in a self-service manner without being blocked by tickets or other lengthy processes.

To achieve that we will use a Port action. In our case it will be a Codefresh pipeline. The action is (like everything else) defined in a terraform file. 

Here’s what it looks like in Port:

1. The developer navigates to the self-service area in Port.

2. They click on a self-service action that we called “Create Everything” (you can use any name you want and have complete freedom in designing the form and inputs), which creates a microservice and all the associated infrastructure. You can see what self-service actions look like in Port’s demo.

3. After the developer completes the self-service action, they are shown a progress window with logs for creating the microservice, supporting long-running and asynchronous actions. You can choose the level of abstraction of detail that is shown to the developers, and in case they want to dive in deeper for any reason (or maybe you need to access some debugging information), you can also add run links to the various pipelines and processes that take care of the action.

What Happens behind the scenes when developers click on the “Create Everything” button?

The developers remain in Port while the necessary actions run on the platform, according to the way you chose to trigger them. Port is platform agnostic and is loosely coupled with the platform. 

In this demo, code and data from the GitHub account and pipeline and clusters in Codefresh are running in the background.

At the same time, the only thing the developer sees is the Log Stream, which updates that the environments, pipelines and GitRepo are being created.

4. When everything is ready, the developer gets a message in the Log Stream that they can commit their code.

After the action finishes, behind the scenes, a brand new repository in GitHub has been set up, including the ability to automatically monitor commits.

In Codefresh, a brand new project was set up and the clusters were updated as well.

In Port, a new microservice was created in the catalog, including a link to the GitHub repo that was just created.

5. The developer can now navigate through Port and see:

  • Which libraries are deployed to which environment:
  • The three environments that were created for them:

Note that nothing here mentions Kuberenetes, because it was decided that this was not important for the developers (this too is customizable). You are free to choose the level of abstraction that fits your developers.

The microservice now exists as a skeleton project in GitHub. Developers can start working on features and any commit will automatically initiate a build (this is already handled by Codefresh natively).

6. To deploy the application, all the developer needs to do is click on a “Build Application” action, choose the microservice and hit “Execute”.

Behind the scenes another build/deployment will run in Codefresh.

Back in Port, a brand new deployment will automatically be created:

A build also shows the docker image that was created. Developer can click on the “details” button and dive into Codefresh for more details.

7. The application is now deployed in the QA environment. It’s time for the developer to promote the microservice to the next environment.

By clicking on the “Promote” action and choosing the right microservice, the microservice can be promoted. For example, from QA to staging.

Conclusion

In this blog post, we showed three complementing demos of Port. These examples show how easy Port is to use and how it simplifies the development process and keeps all stakeholders happy.

For developers, Port enables them to completely self-serve, without having to deal with the parts of development they are not interested in, like Kubernetes.

For DevOps, Port enables them to serve developers without having to be involved or answer tickets. After the initial setup, developers click buttons on their own and get automated Ops services. Port needs something to do the grunt work behind the scenes and in this example we used Codefresh which has more capabilities on its own especially on the GitOps front. Getting more information about deployments is even easier with Codefresh environments.

Finally, Port enables Dev managers to ensure that developers are focused on writing code and that DevOps and SREs are focused on strategic or highly important tasks.

To get started with Port on your own, click here. You can also start using Codefresh for free by creating a new account.

{{cta}}
Developer Portal
DevOps
Developer Experience

Book a demo right now to check out Port's developer portal yourself

{{jenkins}}
Self-Service
Jenkins
Microservices
DevOps
Developer Experience

It's a Trap - Jenkins as Self service UI

{{gitops}}
Developer Experience
GitOps
DevOps
Internal Developer Platform

How do GitOps affect developer experience?

{{ebook}}
Self-Service
Jenkins
Microservices
DevOps
Developer Experience

It's a Trap - Jenkins as Self service UI. Click her to download the eBook

{{cyberark}}
Developer Portal
Developer Velocity
Developer Experience

Learning from CyberArk - building an internal developer platform in-house

{{dropdown}}

Example JSON block

{
  "foo": "bar"
}

Order Domain

{
  "properties": {},
  "relations": {},
  "title": "Orders",
  "identifier": "Orders"
}

Cart System

{
  "properties": {},
  "relations": {
    "domain": "Orders"
  },
  "identifier": "Cart",
  "title": "Cart"
}

Products System

{
  "properties": {},
  "relations": {
    "domain": "Orders"
  },
  "identifier": "Products",
  "title": "Products"
}

Cart Resource

{
  "properties": {
    "type": "postgress"
  },
  "relations": {},
  "icon": "GPU",
  "title": "Cart SQL database",
  "identifier": "cart-sql-sb"
}

Cart API

{
 "identifier": "CartAPI",
 "title": "Cart API",
 "blueprint": "API",
 "properties": {
   "type": "Open API"
 },
 "relations": {
   "provider": "CartService"
 },
 "icon": "Link"
}

Core Kafka Library

{
  "properties": {
    "type": "library"
  },
  "relations": {
    "system": "Cart"
  },
  "title": "Core Kafka Library",
  "identifier": "CoreKafkaLibrary"
}

Core Payment Library

{
  "properties": {
    "type": "library"
  },
  "relations": {
    "system": "Cart"
  },
  "title": "Core Payment Library",
  "identifier": "CorePaymentLibrary"
}

Cart Service JSON

{
 "identifier": "CartService",
 "title": "Cart Service",
 "blueprint": "Component",
 "properties": {
   "type": "service"
 },
 "relations": {
   "system": "Cart",
   "resources": [
     "cart-sql-sb"
   ],
   "consumesApi": [],
   "components": [
     "CorePaymentLibrary",
     "CoreKafkaLibrary"
   ]
 },
 "icon": "Cloud"
}

Products Service JSON

{
  "identifier": "ProductsService",
  "title": "Products Service",
  "blueprint": "Component",
  "properties": {
    "type": "service"
  },
  "relations": {
    "system": "Products",
    "consumesApi": [
      "CartAPI"
    ],
    "components": []
  }
}

Component Blueprint

{
 "identifier": "Component",
 "title": "Component",
 "icon": "Cloud",
 "schema": {
   "properties": {
     "type": {
       "enum": [
         "service",
         "library"
       ],
       "icon": "Docs",
       "type": "string",
       "enumColors": {
         "service": "blue",
         "library": "green"
       }
     }
   },
   "required": []
 },
 "mirrorProperties": {},
 "formulaProperties": {},
 "calculationProperties": {},
 "relations": {
   "system": {
     "target": "System",
     "required": false,
     "many": false
   },
   "resources": {
     "target": "Resource",
     "required": false,
     "many": true
   },
   "consumesApi": {
     "target": "API",
     "required": false,
     "many": true
   },
   "components": {
     "target": "Component",
     "required": false,
     "many": true
   },
   "providesApi": {
     "target": "API",
     "required": false,
     "many": false
   }
 }
}

Resource Blueprint

{
 “identifier”: “Resource”,
 “title”: “Resource”,
 “icon”: “DevopsTool”,
 “schema”: {
   “properties”: {
     “type”: {
       “enum”: [
         “postgress”,
         “kafka-topic”,
         “rabbit-queue”,
         “s3-bucket”
       ],
       “icon”: “Docs”,
       “type”: “string”
     }
   },
   “required”: []
 },
 “mirrorProperties”: {},
 “formulaProperties”: {},
 “calculationProperties”: {},
 “relations”: {}
}

API Blueprint

{
 "identifier": "API",
 "title": "API",
 "icon": "Link",
 "schema": {
   "properties": {
     "type": {
       "type": "string",
       "enum": [
         "Open API",
         "grpc"
       ]
     }
   },
   "required": []
 },
 "mirrorProperties": {},
 "formulaProperties": {},
 "calculationProperties": {},
 "relations": {
   "provider": {
     "target": "Component",
     "required": true,
     "many": false
   }
 }
}

Domain Blueprint

{
 "identifier": "Domain",
 "title": "Domain",
 "icon": "Server",
 "schema": {
   "properties": {},
   "required": []
 },
 "mirrorProperties": {},
 "formulaProperties": {},
 "calculationProperties": {},
 "relations": {}
}

System Blueprint

{
 "identifier": "System",
 "title": "System",
 "icon": "DevopsTool",
 "schema": {
   "properties": {},
   "required": []
 },
 "mirrorProperties": {},
 "formulaProperties": {},
 "calculationProperties": {},
 "relations": {
   "domain": {
     "target": "Domain",
     "required": true,
     "many": false
   }
 }
}
{{tabel-1}}

Microservices SDLC

  • Scaffold a new microservice

  • Deploy (canary or blue-green)

  • Feature flagging

  • Revert

  • Lock deployments

  • Add Secret

  • Force merge pull request (skip tests on crises)

  • Add environment variable to service

  • Add IaC to the service

  • Upgrade package version

Development environments

  • Spin up a developer environment for 5 days

  • ETL mock data to environment

  • Invite developer to the environment

  • Extend TTL by 3 days

Cloud resources

  • Provision a cloud resource

  • Modify a cloud resource

  • Get permissions to access cloud resource

SRE actions

  • Update pod count

  • Update auto-scaling group

  • Execute incident response runbook automation

Data Engineering

  • Add / Remove / Update Column to table

  • Run Airflow DAG

  • Duplicate table

Backoffice

  • Change customer configuration

  • Update customer software version

  • Upgrade - Downgrade plan tier

  • Create - Delete customer

Machine learning actions

  • Train model

  • Pre-process dataset

  • Deploy

  • A/B testing traffic route

  • Revert

  • Spin up remote Jupyter notebook

{{tabel-2}}

Engineering tools

  • Observability

  • Tasks management

  • CI/CD

  • On-Call management

  • Troubleshooting tools

  • DevSecOps

  • Runbooks

Infrastructure

  • Cloud Resources

  • K8S

  • Containers & Serverless

  • IaC

  • Databases

  • Environments

  • Regions

Software and more

  • Microservices

  • Docker Images

  • Docs

  • APIs

  • 3rd parties

  • Runbooks

  • Cron jobs

Check out Port's pre-populated demo and see what it's all about.

(no email required)

Let’s start

Contact sales for a technical product walkthrough

Let’s start

Open a free Port account. No credit card required

Let’s start

Watch Port live coding videos - setting up an internal developer portal & platform

Let’s start

Check out Port's pre-populated demo and see what it's all about.

(no email required)

Let’s start

Contact sales for a technical product walkthrough

Let’s start

Open a free Port account. No credit card required

Let’s start

Watch Port live coding videos - setting up an internal developer portal & platform

Let’s start

Let us walk you through the platform and catalog the assets of your choice.

I’m ready, let’s start