1. Answers
  2. Deploying multi-container applications with Portainer

How Do I Deploy Multi-Container Applications With Portainer?

Introduction

This guide is designed to help you deploy a multi-container application using Portainer on a Kubernetes cluster. Portainer provides a user-friendly management interface for Docker environments, making it easier to manage and deploy applications. By the end of this guide, you will have learned how to set up a Kubernetes namespace, deploy Portainer using a Deployment resource, and expose it with a Service resource, all using Pulumi.

Step-by-Step Explanation

  1. Create a Kubernetes Namespace: Start by creating a dedicated namespace for Portainer to organize your resources within the cluster.

  2. Deploy Portainer: Use a Kubernetes Deployment resource to deploy Portainer. This involves specifying the container image, setting up replicas, and defining volume mounts for persistent storage.

  3. Define Persistent Storage: Set up a PersistentVolumeClaim to ensure that Portainer has the necessary storage for its data, specifying access modes and storage requirements.

  4. Expose Portainer with a Service: Use a Kubernetes Service resource to make Portainer accessible. This includes setting the service type to LoadBalancer and defining the ports through which Portainer can be accessed.

  5. Access Portainer: Finally, export the URL to access the Portainer UI, providing a convenient way to interact with your deployed application.

import * as pulumi from "@pulumi/pulumi";
import * as k8s from "@pulumi/kubernetes";

// Create a namespace for Portainer
const namespace = new k8s.core.v1.Namespace("portainer-ns", {
    metadata: {
        name: "portainer",
    },
});

// Define the Portainer deployment
const portainerDeployment = new k8s.apps.v1.Deployment("portainer-deployment", {
    metadata: {
        namespace: namespace.metadata.name,
        name: "portainer",
    },
    spec: {
        replicas: 1,
        selector: {
            matchLabels: {
                app: "portainer",
            },
        },
        template: {
            metadata: {
                labels: {
                    app: "portainer",
                },
            },
            spec: {
                containers: [
                    {
                        name: "portainer",
                        image: "portainer/portainer-ce:latest",
                        ports: [
                            {
                                containerPort: 9000,
                            },
                        ],
                        volumeMounts: [
                            {
                                name: "data",
                                mountPath: "/data",
                            },
                        ],
                    },
                ],
                volumes: [
                    {
                        name: "data",
                        persistentVolumeClaim: {
                            claimName: "portainer-pvc",
                        },
                    },
                ],
            },
        },
    },
});

// Define the PersistentVolumeClaim for Portainer data
const pvc = new k8s.core.v1.PersistentVolumeClaim("portainer-pvc", {
    metadata: {
        namespace: namespace.metadata.name,
        name: "portainer-pvc",
    },
    spec: {
        accessModes: ["ReadWriteOnce"],
        resources: {
            requests: {
                storage: "10Gi",
            },
        },
    },
});

// Expose Portainer using a Service
const portainerService = new k8s.core.v1.Service("portainer-service", {
    metadata: {
        namespace: namespace.metadata.name,
        name: "portainer",
    },
    spec: {
        type: "LoadBalancer",
        ports: [
            {
                port: 9000,
                targetPort: 9000,
            },
        ],
        selector: {
            app: "portainer",
        },
    },
});

// Export the URL for accessing Portainer
export const portainerUrl = pulumi.interpolate`http://${portainerService.status.loadBalancer.ingress[0].ip}:9000`;

Summary

In this guide, you learned how to deploy a multi-container application using Portainer on a Kubernetes cluster with Pulumi. We covered creating a Kubernetes namespace, deploying Portainer with a Deployment resource, setting up a PersistentVolumeClaim for data storage, and exposing Portainer with a Service. The portainerUrl export provides a direct link to the Portainer UI, allowing you to manage your applications efficiently.

Deploy this code

Want to deploy this code? Sign up for a free Pulumi account to deploy in a few clicks.

Sign up

New to Pulumi?

Want to deploy this code? Sign up with Pulumi to deploy in a few clicks.

Sign up