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
Create a Kubernetes Namespace: Start by creating a dedicated namespace for Portainer to organize your resources within the cluster.
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.
Define Persistent Storage: Set up a PersistentVolumeClaim to ensure that Portainer has the necessary storage for its data, specifying access modes and storage requirements.
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.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 upNew to Pulumi?
Want to deploy this code? Sign up with Pulumi to deploy in a few clicks.
Sign upThank you for your feedback!
If you have a question about how to use Pulumi, reach out in Community Slack.
Open an issue on GitHub to report a problem or suggest an improvement.