Skip to main content
Redhat Developers  Logo
  • Products

    Featured

    • Red Hat Enterprise Linux
      Red Hat Enterprise Linux Icon
    • Red Hat OpenShift AI
      Red Hat OpenShift AI
    • Red Hat Enterprise Linux AI
      Linux icon inside of a brain
    • Image mode for Red Hat Enterprise Linux
      RHEL image mode
    • Red Hat OpenShift
      Openshift icon
    • Red Hat Ansible Automation Platform
      Ansible icon
    • Red Hat Developer Hub
      Developer Hub
    • View All Red Hat Products
    • Linux

      • Red Hat Enterprise Linux
      • Image mode for Red Hat Enterprise Linux
      • Red Hat Universal Base Images (UBI)
    • Java runtimes & frameworks

      • JBoss Enterprise Application Platform
      • Red Hat build of OpenJDK
    • Kubernetes

      • Red Hat OpenShift
      • Microsoft Azure Red Hat OpenShift
      • Red Hat OpenShift Virtualization
      • Red Hat OpenShift Lightspeed
    • Integration & App Connectivity

      • Red Hat Build of Apache Camel
      • Red Hat Service Interconnect
      • Red Hat Connectivity Link
    • AI/ML

      • Red Hat OpenShift AI
      • Red Hat Enterprise Linux AI
    • Automation

      • Red Hat Ansible Automation Platform
      • Red Hat Ansible Lightspeed
    • Developer tools

      • Red Hat Trusted Software Supply Chain
      • Podman Desktop
      • Red Hat OpenShift Dev Spaces
    • Developer Sandbox

      Developer Sandbox
      Try Red Hat products and technologies without setup or configuration fees for 30 days with this shared Openshift and Kubernetes cluster.
    • Try at no cost
  • Technologies

    Featured

    • AI/ML
      AI/ML Icon
    • Linux
      Linux Icon
    • Kubernetes
      Cloud icon
    • Automation
      Automation Icon showing arrows moving in a circle around a gear
    • View All Technologies
    • Programming Languages & Frameworks

      • Java
      • Python
      • JavaScript
    • System Design & Architecture

      • Red Hat architecture and design patterns
      • Microservices
      • Event-Driven Architecture
      • Databases
    • Developer Productivity

      • Developer productivity
      • Developer Tools
      • GitOps
    • Secure Development & Architectures

      • Security
      • Secure coding
    • Platform Engineering

      • DevOps
      • DevSecOps
      • Ansible automation for applications and services
    • Automated Data Processing

      • AI/ML
      • Data Science
      • Apache Kafka on Kubernetes
      • View All Technologies
    • Start exploring in the Developer Sandbox for free

      sandbox graphic
      Try Red Hat's products and technologies without setup or configuration.
    • Try at no cost
  • Learn

    Featured

    • Kubernetes & Cloud Native
      Openshift icon
    • Linux
      Rhel icon
    • Automation
      Ansible cloud icon
    • Java
      Java icon
    • AI/ML
      AI/ML Icon
    • View All Learning Resources

    E-Books

    • GitOps Cookbook
    • Podman in Action
    • Kubernetes Operators
    • The Path to GitOps
    • View All E-books

    Cheat Sheets

    • Linux Commands
    • Bash Commands
    • Git
    • systemd Commands
    • View All Cheat Sheets

    Documentation

    • API Catalog
    • Product Documentation
    • Legacy Documentation
    • Red Hat Learning

      Learning image
      Boost your technical skills to expert-level with the help of interactive lessons offered by various Red Hat Learning programs.
    • Explore Red Hat Learning
  • Developer Sandbox

    Developer Sandbox

    • Access Red Hat’s products and technologies without setup or configuration, and start developing quicker than ever before with our new, no-cost sandbox environments.
    • Explore Developer Sandbox

    Featured Developer Sandbox activities

    • Get started with your Developer Sandbox
    • OpenShift virtualization and application modernization using the Developer Sandbox
    • Explore all Developer Sandbox activities

    Ready to start developing apps?

    • Try at no cost
  • Blog
  • Events
  • Videos

How to simplify your multi-repo workflow with Podman

May 28, 2025
Caleb Evans
Related topics:
ContainersDeveloper ProductivityDeveloper ToolsDevOpsIDEs
Related products:
Podman Desktop

Share:

    I've recently discovered the wonders of development (dev) containers in my workflow. I work on a project with many different components, using various languages, and in some cases, different versions of those languages. These variations from component to component caused me to spend at least an hour or two every week fixing environment-related issues, not to mention the lengthy process of setting up my local environment when I first joined the project.

    I will discuss the methods I used to build a fully containerized dev environment that is consistent, quick to rebuild, and speeds up development. Not only did this solve my problem, it is available for the entire team to use and is incredibly easy for new developers to start using.

    Prerequisites

    To build this environment, you'll need:

    • Podman
    • An integrated development environment (IDE) with support for dev containers. We'll use VS Code for this tutorial.

    Before we dive into the tutorial, there are a few configuration steps in the IDE and Podman:

    1. Enable the compose extension in Podman.
    2. Install the dev containers extension.
    3. Configure the dev containers extension. In the extension settings, set the following values:
      • "Copy Git Config": Enabled 
      • "Docker Compose Path": podman compose
      • "Docker Path": podman
      • "Docker Socket Path": unix:///run/user/1000/podman/podman.sock
        • Note: This value is usually correct. However, you can run the following command to confirm your path: $ podman info --format "{{.Host.RemoteSocket.Path}}"

    Demo repository

    This tutorial uses an accompanying demo repository to explain the concepts. The repo follows this hypothetical setup:

    • Two Quarkus microservices that communicate with each other using Kafka.
    • One Python API that provides external access to the microservices.

    To support these services, we also need:

    • PostgreSQL database
    • Kafka broker
    • ZooKeeper (required by Kafka)

    You can apply the same setup to any combination of technologies or languages. The key takeaway is that these components rely on each other and often need extra infrastructure—like databases and messaging systems—to run properly.

    Creating the dev environment

    The configuration for dev containers is often handled on a per-repository basis. For instance, when you open a repo in VS Code, you might be prompted to create a new dev container config for that repo. While there’s nothing inherently wrong with that approach, it may not be ideal when working with multiple repos. This tutorial shows you how to create a single development repository that everyone on your team can use for an easily repeatable local dev environment. 

    This process consists of six steps:

    1. Start a new repository.
    2. Write your Containerfile(s).
    3. Clone your repos.
    4. Write a Compose file.
    5. Write the dev container configs.
    6. Define environment variables.

    Step 1: Start a new repository

    To begin, create a new repository in your Git platform of choice. This repository will be the gateway to developing the set of components you choose, so name it accordingly. Personally, I use a <name of product>-development format. 

    Next clone the repo and open in your IDE. Then create the following directories:

    • ./Containerfiles: Stores any Containerfiles you may need.
    • ./.devcontainer: Stores all dev container configuration files.

    Step 2: Write your Containerfile(s)

    You can use default dev container images if you’d like, but most users will need to add extra packages or tools. There are many dev container images available from various sources, including Microsoft dev container base images and dev container templates.

    For this tutorial, I’ll use:

    • mcr.microsoft.com/devcontainers/python:3.11 for the API.
    • mcr.microsoft.com/devcontainers/java:17 for the Quarkus microservices.

    In the ./Containerfiles directory, create your Containerfiles. You can name them however you like (e.g., Containerfile.python311 and Containerfile.java17). 

    Here’s an example:

    FROM mcr.microsoft.com/devcontainers/python:3.11
    
    # Set env vars you want for ALL python environments
    ENV HOME="/root"
    ENV PATH="/opt/venv/bin:$PATH"
    
    # Copy in anything you may need.
    # In this example we have a ./Containerfiles/scripts dir to hold any scripts needed after the containers are created.
    COPY --chmod=0755 Containerfiles/scripts /tmp/scripts
    
    # Install any specific packages you may need. 
    # Here we will install a few helpful tools and establish a Python virtual environment.
    RUN apt update -y \
        && apt -y install --no-install-recommends \
            kafkacat \
            curl \
            maven \
            postgresql-client
    
    RUN mkdir -p /opt/venv && \
        python3 -m venv /opt/venv && \
        /opt/venv/bin/pip install --upgrade pip && \
        /opt/venv/bin/pip install pre-commit
        
    CMD ["sleep", "infinity"]

    Step 3: Clone your repos

    This step might sound simple, but it can be tricky if you’re building something for a team. What I mean by "clone your repos" is make sure users clone their forks into a specific directory. You can enforce this with a script. 

    For example, the script could:

    1. Check if ./repos exists.
      • If it does, ask the user if they want to delete it.
      • Or else, create the directory.
    2. Ask for the user's Git username.
    3. Use the username and a pre-defined YAML list of repos (./repos.yaml in the demo) to clone all of their forks to the ./repos directory.

    I would recommend writing your own script to fit your needs. Modifying the one I provide in the demo repo may be a good start. Whatever solution you choose, be sure to add your chosen directory to the repo’s .gitignore.

    Step 4: Write a Compose file

    The Compose file ties everything together. You have a lot of freedom here to define your environment exactly how you need it. You’ll need to define all your components in this file, including supporting infrastructure.

    First, add the components you plan to develop. For example, use the Containerfiles written earlier to build the image. Notice the volumes—one mounts the user's local SSH config (for Git authentication), and the other mounts the directory holding the repos we cloned earlier:

    services:
      microservice-1:
        container_name: microservice-1
        image: "demo-dev-java:17"
        volumes:
          - ~/.ssh:/root/.ssh:cached,z
          - ../repos:/root/repos:cached,z
        networks:
          - demo-network

    Add any supporting infrastructure. For example, here is the Kafka broker service used in the demo:

    kafka:
        hostname: kafka
        image: docker.io/wurstmeister/kafka:latest
        ports:
          - "9092:9092"
        environment:
          - KAFKA_BROKER_ID=1
          - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
          - ALLOW_PLAINTEXT_LISTENER=yes
          - KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT
          - KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092
          - KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092
          - KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT
          - KAFKA_CREATE_TOPICS=demo-topic-one:1:1,demo-topic-two:1:1
        volumes:
          - type: tmpfs
            target: /kafka
        depends_on:
          - zookeeper
        networks:
          - demo-network

    Finally, add the shared network as follows:

    networks:
      demo-network:
        driver: bridge

    Add or configure anything else you may need in your environment. Save this file wherever you prefer. I keep it at ./compose.yaml.

    Step 5: Write the dev container configs

    These configuration files define how your IDE will run within each dev container. The following code snippet is an example devcontainer.json you can tweak to your needs. This example demonstrates a few possibilities, but there are many configuration options to choose from.

    {
      "name": "microservice-1",
      "dockerComposeFile": [
        "../compose.yaml"
      ],
      "service": "microservice-1",
      "workspaceFolder": "/root/repos/microservice-1",
      "updateRemoteUserUID": true,
      "remoteUser": "root",
      "onCreateCommand": "/bin/bash /tmp/scripts/on-create.sh",
      "customizations": {
        "vscode": {
          "settings": {
            "chat.commandCenter.enabled": false,
            "editor.renderWhitespace": "all"
          },
          "extensions": [
            "redhat.java",
            "redhat.vscode-quarkus",
            "redhat.vscode-yaml",
            "redhat.vscode-xml"
          ]
        }
      }
    }

    Organize your .devcontainer folder so each component has its own directory as follows:

    .devcontainer
    ├── api
    │   └── devcontainer.json
    ├── microservice-1
    │   └── devcontainer.json
    ├── microservice-2
    │   └── devcontainer.json

    Here is an explanation of the example config:

    • name: Name of the dev container.
    • dockerComposeFile: References your Compose file.
    • service: The name of the service defined in the Compose file.
    • workspaceFolder: The folder in the container opened by your IDE (here it points to the ./repos directory).
    • updateRemoteUserUID: Matches the UID/GID of the container user to your local user (prevents permissions issues).
    • remoteUser: Which user to run as in the container.
    • onCreateCommand: Command to run after the container is created.
    • customizations: Defines IDE settings and extensions.

    Step 6: Define environment variables

    If you need environment variables, you can either add them directly in the Compose file or define them in a file and reference that in the Compose file. It’s often helpful to have a single common.env file for variables used across components and individual *.env files for variables specific to each component as follows:

    .devcontainer
    ├── api
    │   └── devcontainer.json
    │   └── var.env
    ├── microservice-1
    │   └── devcontainer.json
    │   └── var.env
    ├── microservice-2
    │   └── devcontainer.json
    │   └── var.env
    └── common.env

    The following is in the Compose file:

    services:
      microservice-1:
        container_name: microservice-1
        image: "demo-dev-java:17"
        env_file:
          - ./common.env
          - ./microservice-1/var.env
        volumes:
          - ~/.ssh:/root/.ssh:cached,z
          - ../repos:/root/repos:cached,z
        networks:
          - demo-network

    Set up the dev environment

    To set up the environment:

    1. Build the images using the Containerfiles you created, making sure to match the Compose file’s image name: podman build -f ./Containerfiles/Containerfile.java17 -t demo-dev-java:17 .

    Note:

    To streamline this process, you could build the images in CI and publish them to an image registry or add these commands to a Makefile.

    1. Make sure your repos are cloned.

    Open the environment in a container

    Next open the environment in a container:

    1. Open the new *-development (or whatever you named it) repo in VS Code, if you haven't already.
    2. Open the command palette by entering: CTRL + SHIFT + P.
    3. Search for and select: Dev Containers: Reopen in Container.
    4. Select the name of the component you want to start developing.

    After you select the component, the window will appear blank and show a status bar in the bottom-right corner. You can decide if you want to watch the startup logs. It may take a few minutes, depending on what kind of scripts you have set up to run on start up. The first time you do this, it may take additional time because you also need to create all of the containers.

    Switch to a different component

    To switch to an alternate component:

    1. Open the command palette by entering: CTRL + SHIFT + P.
    2. Search for and select: Dev Containers: Switch Container.
    3. Select the name of the component you want to switch to.

    Rebuild the containers

    When you break something, just rebuild the environment as follows:

    1. Open the command palette by entering: CTRL + SHIFT + P.
    2. Search for and select: Dev Containers: Rebuild Container.

    This will destroy the environment and rebuild it. You will not lose progress on any work as it is stored locally and mounted to the containers.

    Next steps

    This tutorial only scratches the surface of what’s possible. Check out the official documentation for more ideas.

    • Compose specification
    • Dev containers specification

    Related Posts

    • Four creative ways to create an OpenShift/Kubernetes dev environment

    • Build and run Buildah inside a Podman container

    • Monitoring container vitality and availability with Podman

    • Introducing IDE support for Apache Camel K Modeline

    Recent Posts

    • GuideLLM: Evaluate LLM deployments for real-world inference

    • Unleashing multimodal magic with RamaLama

    • Integrate Red Hat AI Inference Server & LangChain in agentic workflows

    • Streamline multi-cloud operations with Ansible and ServiceNow

    • Automate dynamic application security testing with RapiDAST

    What’s up next?

    This learning path demonstrates the full lifecycle of how you can go from an initial application, to a container, to a fully running Pod on Kubernetes in 30 minutes using Podman Desktop and the Developer Sandbox.

    Start the activity
    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Products

    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform

    Build

    • Developer Sandbox
    • Developer Tools
    • Interactive Tutorials
    • API Catalog

    Quicklinks

    • Learning Resources
    • E-books
    • Cheat Sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site Status Dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Report a website issue