2021-11-08 16:04:20 -06:00
---
2023-03-14 11:25:48 -07:00
title_tag: Configuring & Provisioning Containers | Learn Pulumi
2021-11-08 16:04:20 -06:00
title: "Configuring and Provisioning Containers"
layout: topic
date: 2021-09-07T14:12:59-05:00
draft: false
description: Configure and provision your first containers locally with Pulumi.
2023-03-14 11:25:48 -07:00
meta_desc: Learn how to configure and provision your first containers locally with Pulumi in this tutorial.
2021-11-08 16:04:20 -06:00
index: 2
estimated_time: 10
meta_image: meta.png
authors:
- sophia-parafina
- laura-santamaria
tags:
- fundamentals
- configuration
- provisioning
- containers
- docker
links:
- text: Code Repo
url: https://github.com/pulumi/tutorial-pulumi-fundamentals
---
Now that we've created our images, we can provision our application with a
network and containers. First, we're going to add configuration to our Pulumi
program. Pulumi is a tool to
2023-05-15 15:25:28 -07:00
[configure ](/docs/concepts/config/ ) your infrastructure,
2021-11-08 16:04:20 -06:00
and that includes being able to configure the different stacks with different
values. As a result, it makes sense to include the basic configurations as
variables at the top of your program.
## Configure the application
2022-05-03 21:23:32 -07:00
Add the following configuration variables to your Pulumi program:
2021-11-08 16:04:20 -06:00
2022-12-19 10:14:04 -07:00
{{< chooser language " typescript , python , go , java , yaml " / > }}
2022-02-10 08:46:56 -08:00
{{% choosable language typescript %}}
2022-05-03 21:23:32 -07:00
These configuration declarations go below your imports.
2022-02-10 08:46:56 -08:00
```typescript
2022-12-19 10:14:04 -07:00
// Get configuration values
2022-02-10 08:46:56 -08:00
const config = new pulumi.Config();
2022-05-03 21:23:32 -07:00
const frontendPort = config.requireNumber("frontendPort");
const backendPort = config.requireNumber("backendPort");
const mongoPort = config.requireNumber("mongoPort");
2022-02-10 08:46:56 -08:00
```
{{% /choosable %}}
2021-11-08 16:04:20 -06:00
{{% choosable language python %}}
2022-05-03 21:23:32 -07:00
These configuration declarations go below your imports.
2021-11-08 16:04:20 -06:00
```python
2022-12-19 10:14:04 -07:00
# Get configuration values
2021-11-08 16:04:20 -06:00
config = pulumi.Config()
2022-05-03 21:23:32 -07:00
frontend_port = config.require_int("frontendPort")
backend_port = config.require_int("backendPort")
mongo_port = config.require_int("mongoPort")
```
{{% /choosable %}}
2022-12-19 10:14:04 -07:00
{{% choosable language go %}}
First, add this to the end of your `import` section:
```go
"github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
```
Run `go mod tidy` to update the `go.mod` and `go.sum` files as necessary.
Next, add these configuration declarations near the top of the `main()` function, just after the `pulumi.Run` line.
```go
// Get configuration values
cfg := config.New(ctx, "")
frontendPort := cfg.RequireFloat64("frontendPort")
backendPort := cfg.RequireFloat64("backendPort")
mongoPort := cfg.RequireFloat64("mongoPort")
_ = frontendPort + backendPort + mongoPort
```
That last line is, again, just to satisfy Go's requirement that no variables can be declared that aren't used later. We'll remove this as we proceed.
{{% /choosable %}}
2022-05-03 21:23:32 -07:00
{{% choosable language java %}}
2022-05-05 14:18:45 -05:00
These configuration declarations go in the static `stack()` method:
2022-05-03 21:23:32 -07:00
```java
2022-12-19 10:14:04 -07:00
// Get configuration values
2022-08-31 13:57:44 -05:00
final var config = ctx.config();
final var frontendPort = config.requireInteger("frontendPort");
final var backendPort = config.requireInteger("backendPort");
final var mongoPort = config.requireInteger("mongoPort");
2022-05-03 21:23:32 -07:00
```
{{% /choosable %}}
{{% choosable language yaml %}}
2022-09-01 10:35:26 -05:00
These statements go between the `description` and the `resources` where `configuration` and `variables` have been:
2022-05-03 21:23:32 -07:00
```yaml
2022-12-19 10:14:04 -07:00
# Get configuration values
2022-05-03 21:23:32 -07:00
configuration:
frontendPort:
2022-09-01 10:35:26 -05:00
type: Number
2022-05-03 21:23:32 -07:00
backendPort:
2022-09-01 10:35:26 -05:00
type: Number
2022-05-03 21:23:32 -07:00
mongoPort:
2022-09-01 10:35:26 -05:00
type: Number
2022-12-19 10:14:04 -07:00
# Define variables
2022-05-03 21:23:32 -07:00
variables:
backendImageName: backend
frontendImageName: frontend
2021-11-08 16:04:20 -06:00
```
{{% /choosable %}}
2022-12-21 16:48:29 -07:00
You'll end up using these configuration values later, passing them as environment variables to the containers.
2021-11-08 20:14:32 -06:00
Your Pulumi program should now match this code:
2021-11-08 16:04:20 -06:00
2022-12-19 10:14:04 -07:00
{{< chooser language " typescript , python , go , java , yaml " / > }}
2022-02-10 08:46:56 -08:00
{{% choosable language typescript %}}
```typescript
import * as pulumi from "@pulumi/pulumi ";
import * as docker from "@pulumi/docker ";
2022-12-19 10:14:04 -07:00
// Get configuration values
2022-02-10 08:46:56 -08:00
const config = new pulumi.Config();
2022-05-03 21:23:32 -07:00
const frontendPort = config.requireNumber("frontendPort");
const backendPort = config.requireNumber("backendPort");
const mongoPort = config.requireNumber("mongoPort");
2022-02-10 08:46:56 -08:00
const stack = pulumi.getStack();
2022-12-19 10:14:04 -07:00
// Pull the backend image
2022-02-10 08:46:56 -08:00
const backendImageName = "backend";
2022-12-19 10:14:04 -07:00
const backend = new docker.RemoteImage(`${backendImageName}Image` , {
2022-05-03 21:23:32 -07:00
name: "pulumi/tutorial-pulumi-fundamentals-backend:latest",
2022-02-10 08:46:56 -08:00
});
2022-12-19 10:14:04 -07:00
// Pull the frontend image
2022-02-10 08:46:56 -08:00
const frontendImageName = "frontend";
2022-12-19 10:14:04 -07:00
const frontend = new docker.RemoteImage(`${frontendImageName}Image` , {
2022-05-03 21:23:32 -07:00
name: "pulumi/tutorial-pulumi-fundamentals-frontend:latest",
2022-02-10 08:46:56 -08:00
});
2022-12-19 10:14:04 -07:00
// Pull the MongoDB image
const mongoImage = new docker.RemoteImage("mongoImage", {
2022-05-03 21:23:32 -07:00
name: "pulumi/tutorial-pulumi-fundamentals-database-local:latest",
2022-02-10 08:46:56 -08:00
});
```
{{% /choosable %}}
2021-11-08 16:04:20 -06:00
{{% choosable language python %}}
```python
import pulumi
import pulumi_docker as docker
2022-12-19 10:14:04 -07:00
# Get configuration values
2021-11-08 16:04:20 -06:00
config = pulumi.Config()
frontend_port = config.require_int("frontend_port")
backend_port = config.require_int("backend_port")
mongo_port = config.require_int("mongo_port")
stack = pulumi.get_stack()
2022-12-19 10:14:04 -07:00
# Pull the backend image
2021-11-08 16:04:20 -06:00
backend_image_name = "backend"
2022-12-19 10:14:04 -07:00
backend = docker.RemoteImage(f"{backend_image_name}_image",
2022-05-03 21:23:32 -07:00
name="pulumi/tutorial-pulumi-fundamentals-backend:latest"
)
2021-11-08 16:04:20 -06:00
2022-12-19 10:14:04 -07:00
# Pull the frontend image
2021-11-08 16:04:20 -06:00
frontend_image_name = "frontend"
2022-12-19 10:14:04 -07:00
frontend = docker.RemoteImage(f"{frontend_image_name}_image",
2022-05-03 21:23:32 -07:00
name="pulumi/tutorial-pulumi-fundamentals-frontend:latest"
)
2021-11-08 16:04:20 -06:00
2022-12-19 10:14:04 -07:00
# Pull the MongoDB image
mongo_image = docker.RemoteImage("mongo_image",
2022-05-03 21:23:32 -07:00
name="pulumi/tutorial-pulumi-fundamentals-database-local:latest"
)
```
{{% /choosable %}}
2022-12-19 10:14:04 -07:00
{{% choosable language go %}}
```go
package main
import (
"fmt"
"github.com/pulumi/pulumi-docker/sdk/v3/go/docker"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
// Get configuration values
cfg := config.New(ctx, "")
frontendPort := cfg.RequireFloat64("frontendPort")
backendPort := cfg.RequireFloat64("backendPort")
mongoPort := cfg.RequireFloat64("mongoPort")
_ = frontendPort + backendPort + mongoPort
// Pull the backend image
backendImageName := "backend"
backendImage, err := docker.NewRemoteImage(ctx, fmt.Sprintf("%v-image", backendImageName), & docker.RemoteImageArgs{
Name: pulumi.String("pulumi/tutorial-pulumi-fundamentals-backend:latest"),
})
if err != nil {
return err
}
ctx.Export("backendDockerImage", backendImage.Name)
// Pull the frontend image
frontendImageName := "frontend"
frontendImage, err := docker.NewRemoteImage(ctx, fmt.Sprintf("%v-image", frontendImageName), & docker.RemoteImageArgs{
Name: pulumi.String("pulumi/tutorial-pulumi-fundamentals-frontend:latest"),
})
if err != nil {
return err
}
ctx.Export("frontendDockerImage", frontendImage.Name)
// Pull the MongoDB image
mongoImage, err := docker.NewRemoteImage(ctx, "mongo-image", & docker.RemoteImageArgs{
Name: pulumi.String("pulumi/tutorial-pulumi-fundamentals-database-local:latest"),
})
if err != nil {
return err
}
ctx.Export("mongoDockerImage", mongoImage.Name)
return nil
})
}
```
{{% /choosable %}}
2022-05-03 21:23:32 -07:00
{{% choosable language java %}}
```java
package my_first_app;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.docker.RemoteImage;
import com.pulumi.docker.RemoteImageArgs;
import java.util.List;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
2022-05-05 14:18:45 -05:00
private static void stack(Context ctx) {
2022-12-19 10:14:04 -07:00
// Get configuration values
2022-08-31 13:57:44 -05:00
final var config = ctx.config();
final var frontendPort = config.requireInteger("frontendPort");
final var backendPort = config.requireInteger("backendPort");
final var mongoPort = config.requireInteger("mongoPort");
2022-05-03 21:23:32 -07:00
final var stackName = ctx.stackName();
2022-12-19 10:14:04 -07:00
// Pull the backend image
2022-05-03 21:23:32 -07:00
final String backendImageName = "backend";
2022-08-31 13:57:44 -05:00
final var backendImage = new RemoteImage(
2022-05-03 21:23:32 -07:00
backendImageName,
RemoteImageArgs.builder()
.name(String.format("pulumi/tutorial-pulumi-fundamentals-%s:latest",backendImageName))
.build()
);
2022-12-19 10:14:04 -07:00
// Pull the frontend image
2022-05-03 21:23:32 -07:00
final String frontendImageName = "frontend";
2022-08-31 13:57:44 -05:00
final var frontendImage = new RemoteImage(
2022-05-03 21:23:32 -07:00
frontendImageName,
RemoteImageArgs.builder()
.name(String.format("pulumi/tutorial-pulumi-fundamentals-%s:latest",frontendImageName))
.build()
);
2022-12-19 10:14:04 -07:00
// Pull the MongoDB image
2022-08-31 13:57:44 -05:00
final var mongoImage = new RemoteImage(
2022-05-03 21:23:32 -07:00
"mongoImage",
RemoteImageArgs.builder()
.name("pulumi/tutorial-pulumi-fundamentals-database-local:latest")
.build()
);
2022-08-31 13:57:44 -05:00
}
}
2022-05-03 21:23:32 -07:00
```
{{% /choosable %}}
{{% choosable language yaml %}}
```yaml
2022-09-01 10:35:26 -05:00
name: my_first_app
2022-05-03 21:23:32 -07:00
runtime: yaml
2022-09-01 10:35:26 -05:00
description: A minimal Pulumi YAML program
2022-12-19 10:14:04 -07:00
# Get configuration values
2022-05-03 21:23:32 -07:00
configuration:
frontendPort:
2022-09-01 10:35:26 -05:00
type: Number
2022-05-03 21:23:32 -07:00
backendPort:
2022-09-01 10:35:26 -05:00
type: Number
2022-05-03 21:23:32 -07:00
mongoPort:
2022-09-01 10:35:26 -05:00
type: Number
2022-12-19 10:14:04 -07:00
# Define variables
2022-05-03 21:23:32 -07:00
variables:
backendImageName: backend
frontendImageName: frontend
resources:
2022-12-19 10:14:04 -07:00
# Pull the backend image
2022-05-03 21:23:32 -07:00
backend-image:
type: docker:index:RemoteImage
properties:
name: pulumi/tutorial-pulumi-fundamentals-backend:latest
2022-12-19 10:14:04 -07:00
# Pull the frontend image
2022-05-03 21:23:32 -07:00
frontend-image:
type: docker:index:RemoteImage
properties:
name: pulumi/tutorial-pulumi-fundamentals-frontend:latest
2022-12-19 10:14:04 -07:00
# Pull the MongoDB image
mongo-image:
type: docker:index:RemoteImage
properties:
name: pulumi/tutorial-pulumi-fundamentals-database-local:latest
2022-09-01 10:35:26 -05:00
outputs: {}
2021-11-08 16:04:20 -06:00
```
{{% /choosable %}}
2022-12-19 10:14:04 -07:00
Try and run your `pulumi up` again at this point. You should get an error that looks something like this:
2021-11-08 16:04:20 -06:00
```bash
Diagnostics:
2022-05-03 21:23:32 -07:00
pulumi:pulumi:Stack (my_first_app-dev):
error: Missing required configuration variable 'my_first_app:frontendPort'
please set a value using the command `pulumi config set my_first_app:frontendPort <value>`
error: an unhandled error occurred: < ... > exited with non-zero exit code: 1
2021-11-08 16:04:20 -06:00
```
This is because we have specified that this config option is _required_ .
Remember how we can use the same program to define multiple stacks? Let's set
the ports for this stack, which the Pulumi command line knows already from when
you first initialized the project (it's the `dev` stack by default):
```bash
2022-05-03 21:23:32 -07:00
pulumi config set frontendPort 3001
pulumi config set backendPort 3000
pulumi config set mongoPort 27017
2021-11-08 16:04:20 -06:00
```
This set of commands creates a file in your directory called `Pulumi.dev.yaml`
to store the configuration for this stack.
2023-10-26 17:55:02 +02:00
The content of the file should be like this:
```yaml
config:
my_first_app:backendPort: "3000"
my_first_app:frontendPort: "3001"
my_first_app:mongoPort: "27017"
```
Now, try and rerun your Pulumi program with `pulumi up` command.
2021-11-08 16:04:20 -06:00
Your Pulumi program should now run, but you're not actually using these newly
configured ports just yet! That's because we don't have any container resources
that use the ports; we only have image resources.
## Create a Container resource
2022-12-21 16:48:29 -07:00
In the last topic, we retrieved Docker images from a remote registry. Now we want to create Docker containers and pass these containers the configuration values we just defined. Our containers will need to connect to each other, so we will need to create a [`Network` ](/registry/packages/docker/api-docs/network ), which is another resource.
2021-11-08 16:04:20 -06:00
2022-12-19 10:14:04 -07:00
{{< chooser language " typescript , python , go , java , yaml " / > }}
2022-02-10 08:46:56 -08:00
{{% choosable language typescript %}}
2022-09-01 10:35:26 -05:00
Add the following code at the bottom of your program:
2022-02-10 08:46:56 -08:00
```typescript
2022-12-19 10:14:04 -07:00
// Create a Docker network
2022-02-10 08:46:56 -08:00
const network = new docker.Network("network", {
name: `services-${stack}` ,
});
```
{{% /choosable %}}
2021-11-08 16:04:20 -06:00
{{% choosable language python %}}
2022-09-01 10:35:26 -05:00
Add the following code at the bottom of your program:
2021-11-08 16:04:20 -06:00
```python
2022-12-19 10:14:04 -07:00
# Create a Docker network
network = docker.Network("network", name=f"services_{stack}")
```
{{% /choosable %}}
{{% choosable language go %}}
Add this code at the bottom of your program, just before the last `return nil` statement:
```go
// Create a Docker network
network, err := docker.NewNetwork(ctx, "network", & docker.NetworkArgs{
Name: pulumi.String(fmt.Sprintf("services-%v", ctx.Stack())),
})
if err != nil {
return err
}
ctx.Export("containerNetwork", network.Name)
2021-11-08 16:04:20 -06:00
```
{{% /choosable %}}
2022-05-03 21:23:32 -07:00
{{% choosable language java %}}
2022-05-05 14:18:45 -05:00
Add these imports to the top:
```java
import com.pulumi.docker.Network;
import com.pulumi.docker.NetworkArgs;
import com.pulumi.docker.Container;
import com.pulumi.docker.ContainerArgs;
import com.pulumi.docker.inputs.ContainerNetworksAdvancedArgs;
import com.pulumi.docker.inputs.ContainerPortArgs;
import com.pulumi.resources.CustomResourceOptions;
```
Add this code at the bottom:
2022-05-03 21:23:32 -07:00
```java
2022-12-19 10:14:04 -07:00
// Create a Docker Network
2022-08-31 13:57:44 -05:00
final var network = new Network(
2022-05-03 21:23:32 -07:00
"network",
NetworkArgs.builder()
.name(String.format("services-%s",stackName))
.build()
);
```
{{% /choosable %}}
{{% choosable language yaml %}}
2022-09-01 10:35:26 -05:00
Add the following code at the bottom of your `resources` section:
2022-05-03 21:23:32 -07:00
```yaml
2022-12-19 10:14:04 -07:00
# Create a Docker network
network:
type: docker:index:Network
properties:
name: services-${pulumi.stack}
2022-05-03 21:23:32 -07:00
```
{{% /choosable %}}
2021-11-08 16:04:20 -06:00
Define a new
2022-10-26 07:22:15 -07:00
[`Container` ](/registry/packages/docker/api-docs/container )
2021-11-08 16:04:20 -06:00
resource in your Pulumi program below the `Network` resource, like this:
2022-12-19 10:14:04 -07:00
{{< chooser language " typescript , python , go , java , yaml " / > }}
2022-02-10 08:46:56 -08:00
{{% choosable language typescript %}}
```typescript
2022-12-19 10:14:04 -07:00
// Create the backend container
2022-02-10 08:46:56 -08:00
const backendContainer = new docker.Container("backendContainer", {
name: `backend-${stack}` ,
2022-05-03 21:23:32 -07:00
image: backend.repoDigest,
2022-02-10 08:46:56 -08:00
ports: [
{
internal: backendPort,
external: backendPort,
},
],
envs: [
`DATABASE_HOST=${mongoHost}` ,
`DATABASE_NAME=${database}` ,
`NODE_ENV=${nodeEnvironment}` ,
],
networksAdvanced: [
{
name: network.name,
},
],
}, { dependsOn: [ mongoContainer ]});
```
{{% /choosable %}}
2021-11-08 16:04:20 -06:00
{{% choosable language python %}}
```python
2022-12-19 10:14:04 -07:00
# Create the backend container
2021-11-08 16:04:20 -06:00
backend_container = docker.Container("backend_container",
name=f"backend-{stack}",
2022-05-03 21:23:32 -07:00
image=backend.repo_digest,
2021-11-08 16:04:20 -06:00
ports=[docker.ContainerPortArgs(
internal=backend_port,
external=backend_port)],
envs=[
f"DATABASE_HOST={mongo_host}",
f"DATABASE_NAME={database}",
f"NODE_ENV={node_environment}"
],
networks_advanced=[docker.ContainerNetworksAdvancedArgs(
name=network.name
)],
opts=pulumi.ResourceOptions(depends_on=[mongo_container])
)
```
{{% /choosable %}}
2022-12-19 10:14:04 -07:00
{{% choosable language go %}}
```go
// Create the backend container
// Use _ instead of a variable name since this container isn't referenced
_, err = docker.NewContainer(ctx, "backend-container", & docker.ContainerArgs{
Name: pulumi.String(fmt.Sprintf("backend-%v", ctx.Stack())),
Image: backendImage.RepoDigest,
Ports: & docker.ContainerPortArray{
& docker.ContainerPortArgs{
Internal: pulumi.Int(backendPort),
External: pulumi.Int(backendPort),
},
},
Envs: pulumi.StringArray{
pulumi.String(fmt.Sprintf("DATABASE_HOST=%v", mongoHost)),
pulumi.String(fmt.Sprintf("DATABASE_NAME=%v", database)),
pulumi.String(fmt.Sprintf("NODE_ENV=%v", nodeEnvironment)),
},
NetworksAdvanced: & docker.ContainerNetworksAdvancedArray{
& docker.ContainerNetworksAdvancedArgs{
Name: network.Name,
Aliases: pulumi.StringArray{
pulumi.String(fmt.Sprintf("backend-%v", ctx.Stack())),
},
},
},
}, pulumi.DependsOn([]pulumi.Resource{
mongoContainer,
}))
if err != nil {
return err
}
```
Because we now have something that is referencing the `backendImage` and `network` resources we defined earlier, we can now remove the `ctx.Export` statements for those resources from our code.
{{% /choosable %}}
2022-05-03 21:23:32 -07:00
{{% choosable language java %}}
```java
2022-12-19 10:14:04 -07:00
// Create the backend container
2022-08-31 13:57:44 -05:00
final var backendContainer = new Container(
2022-05-03 21:23:32 -07:00
"backendContainer",
ContainerArgs.builder()
.name(String.format("backend-%s",stackName))
.image(backendImage.repoDigest())
.ports(ContainerPortArgs.builder()
.internal(backendPort)
.external(backendPort)
.build())
.envs(List.of(
String.format("DATABASE_HOST=%s",mongoHost),
String.format("DATABASE_NAME=%s",database),
2022-07-13 11:16:30 -06:00
String.format("NODE_ENV=%s",nodeEnvironment)
2022-05-03 21:23:32 -07:00
))
.networksAdvanced(ContainerNetworksAdvancedArgs.builder()
.name(network.name())
.build()
)
.build(),
CustomResourceOptions.builder()
.dependsOn(mongoContainer)
.build()
);
```
{{% /choosable %}}
{{% choosable language yaml %}}
```yaml
2022-12-19 10:14:04 -07:00
# Create the backend container
backend-container:
type: docker:index:Container
properties:
name: ${backendImageName}-${pulumi.stack}
image: ${backend-image.repoDigest}
ports:
- internal: ${backendPort}
external: ${backendPort}
envs:
[
"DATABASE_HOST=${mongoHost}",
"DATABASE_NAME=${database}",
"NODE_ENV=${nodeEnvironment}"
]
networksAdvanced:
- name: ${network.name}
aliases: ["${backendImageName}-${pulumi.stack}"]
options:
dependsOn:
- ${mongo-container}
2022-05-03 21:23:32 -07:00
```
{{% /choosable %}}
2022-02-10 08:46:56 -08:00
{{% choosable language typescript %}}
2022-05-03 21:23:32 -07:00
It is important to note something here. In the `Container` resource, we are referencing `repoDigest` from the `RemoteImage` resource. Pulumi now knows there is a dependency between these two resources and will know to create the `Container` resource _after_ the `RemoteImage` resource. Another dependency to note is that the `backendContainer` depends on the `mongoContainer` . If we tried to run `pulumi up` without the `mongoContainer` running or present somewhere in state, Pulumi would let us know that the resource didn't exist and would stop.
2022-02-10 08:46:56 -08:00
{{% /choosable %}}
{{% choosable language python %}}
2022-05-03 21:23:32 -07:00
It is important to note something here. In the `Container` resource, we are referencing `repo_digest` from the `RemoteImage` resource. Pulumi now knows there is a dependency between these two resources and will know to create the `Container` resource _after_ the `Image` resource. Another dependency to note is that the `backend_container` depends on the `mongo_container` . If we tried to run `pulumi up` without the `mongo_container` running or present somewhere in state, Pulumi would let us know that the resource didn't exist and would stop.
{{% /choosable %}}
2022-12-19 10:14:04 -07:00
{{% choosable language go %}}
It is important to note something here. In the `Container` resource, we are referencing `repoDigest` from the `RemoteImage` resource. Pulumi now knows there is a dependency between these two resources and will know to create the `Container` resource _after_ the `RemoteImage` resource. Another dependency to note is that the `backendContainer` depends on the `mongoContainer` . If we tried to run `pulumi up` without the `mongoContainer` running or present somewhere in state, Pulumi would let us know that the resource didn't exist and would stop.
{{% /choosable %}}
2022-05-03 21:23:32 -07:00
{{% choosable language java %}}
It is important to note something here. In the `Container` resource, we are referencing `repoDigest` from the `RemoteImage` resource. Pulumi now knows there is a dependency between these two resources and will know to create the `Container` resource _after_ the `RemoteImage` resource. Another dependency to note is that the `backendContainer` depends on the `mongoContainer` . If we tried to run `pulumi up` without the `mongoContainer` running or present somewhere in state, Pulumi would let us know that the resource didn't exist and would stop.
{{% /choosable %}}
{{% choosable language yaml %}}
It is important to note something here. In the `Container` resource, we are referencing `repoDigest` from the `RemoteImage` resource. Pulumi now knows there is a dependency between these two resources and will know to create the `Container` resource _after_ the `RemoteImage` resource. Another dependency to note is that the `backend-container` depends on the `mongo-container` . If we tried to run `pulumi up` without the `mongo-container` running or present somewhere in state, Pulumi would let us know that the resource didn't exist and would stop.
2021-11-08 16:04:20 -06:00
2022-02-10 08:46:56 -08:00
{{% /choosable %}}
2022-12-21 16:48:29 -07:00
It's also important to note the backend container requires some environment variables to connect to the Mongo container and to set the Node environment for Express.js. These are set in the `backend/src/.env` file in the [tutorial-pulumi-fundamentals ](https://github.com/pulumi/tutorial-pulumi-fundamentals/tree/main/backend ) repository. We don't want to hardcode these values; we want them to be configurable. To do that, we'll need to define some additional configuration values. Like before, we can set them using `pulumi config` on the command line:
2021-11-08 16:04:20 -06:00
```bash
2022-05-03 21:23:32 -07:00
pulumi config set mongoHost mongodb://mongo:27017
2021-11-08 16:04:20 -06:00
pulumi config set database cart
2022-05-03 21:23:32 -07:00
pulumi config set nodeEnvironment development
2022-05-05 14:18:45 -05:00
pulumi config set protocol http://
2021-11-08 16:04:20 -06:00
```
Then, we need to add them to the top of our program with the rest of the
2022-12-21 16:48:29 -07:00
configuration values.
2021-11-08 16:04:20 -06:00
2022-12-19 10:14:04 -07:00
{{< chooser language " typescript , python , go , java , yaml " / > }}
2022-02-10 08:46:56 -08:00
{{% choosable language typescript %}}
```typescript
2022-05-03 21:23:32 -07:00
const mongoHost = config.require("mongoHost"); // Note that strings are the default, so it's not `config.requireString` , just `config.require` .
2022-02-10 08:46:56 -08:00
const database = config.require("database");
2022-05-03 21:23:32 -07:00
const nodeEnvironment = config.require("nodeEnvironment");
const protocol = config.require("protocol")
2022-02-10 08:46:56 -08:00
```
{{% /choosable %}}
2021-11-08 16:04:20 -06:00
{{% choosable language python %}}
```python
2022-05-03 21:23:32 -07:00
mongo_host = config.require("mongoHost") # Note that strings are the default, so it's not `config.require_str` , just `config.require` .
2021-11-08 16:04:20 -06:00
database = config.require("database")
2022-05-03 21:23:32 -07:00
node_environment = config.require("nodeEnvironment")
protocol = config.require("protocol")
```
{{% /choosable %}}
2022-12-19 10:14:04 -07:00
{{% choosable language go %}}
```go
mongoHost := cfg.Require("mongoHost") // Note that strings are the default, so it's not `cfg.RequireStr` , just `cfg.Require`
database := cfg.Require("database")
nodeEnvironment := cfg.Require("nodeEnvironment")
protocol := cfg.Require("protocol")
```
{{% /choosable %}}
2022-05-03 21:23:32 -07:00
{{% choosable language java %}}
```java
2022-12-19 10:14:04 -07:00
final var mongoHost = config.require("mongoHost"); // Note that strings are the default, so it's not `config.requireString` , just `config.require`
2022-08-31 13:57:44 -05:00
final var database = config.require("database");
final var nodeEnvironment = config.require("nodeEnvironment");
final var protocol = config.require("protocol");
2022-05-03 21:23:32 -07:00
```
{{% /choosable %}}
{{% choosable language yaml %}}
```yaml
2022-12-19 10:14:04 -07:00
mongoHost:
type: string
database:
type: string
nodeEnvironment:
type: string
protocol:
type: string
2021-11-08 16:04:20 -06:00
```
{{% /choosable %}}
2022-12-21 16:48:29 -07:00
All these configuration values are set as required, meaning if you forget to set them with `pulumi config set` , then `pulumi up` will report an error.
2022-02-10 08:46:56 -08:00
{{% choosable language typescript %}}
2022-12-19 10:14:04 -07:00
We also need to create `Container` resources for the frontend and Mongo
containers. Put the `mongoContainer` declaration just before the `backendContainer` one, and the
`frontendContainer` declaration after the `backendContainer` declaration. Here's the code for the Mongo container:
2022-02-10 08:46:56 -08:00
{{% /choosable %}}
{{% choosable language python %}}
2022-12-19 10:14:04 -07:00
We also need to create `Container` resources for the frontend and Mongo
containers. Put the `mongo_container` declaration just before the `backend_container` one, and the
`frontend_container` declaration after `backend_container` . Here's the code for the Mongo container:
{{% /choosable %}}
{{% choosable language go %}}
We also need to create `Container` resources for the frontend and Mongo
containers. Put the `mongoContainer` declaration just before the declaration for the backend container and declaration for the frontend container just after the declaration for the backend container. Here's the code for the Mongo container:
2021-11-08 16:04:20 -06:00
2022-02-10 08:46:56 -08:00
{{% /choosable %}}
2022-05-03 21:23:32 -07:00
{{% choosable language java %}}
2022-12-19 10:14:04 -07:00
We also need to create `Container` resources for the frontend and Mongo containers. Put the `mongoContainer` declaration just before the `backendContainer` one, and the `frontendContainer` declaration after the declaration for `backendContainer` . Here's the code for the Mongo container:
2022-05-03 21:23:32 -07:00
{{% /choosable %}}
{{% choosable language yaml %}}
2022-12-19 10:14:04 -07:00
We also need to create `Container` resources for the frontend and Mongo containers. Put the `mongo-container` declaration just before the `backend-container` one, and the `frontend-container` declaration after the `backend-container` declaration. Here's the code for the Mongo container:
2022-05-03 21:23:32 -07:00
{{% /choosable %}}
2022-12-19 10:14:04 -07:00
{{< chooser language " typescript , python , go , java , yaml " / > }}
2022-02-10 08:46:56 -08:00
{{% choosable language typescript %}}
```typescript
2022-12-19 10:14:04 -07:00
// Create the MongoDB container
2022-02-10 08:46:56 -08:00
const mongoContainer = new docker.Container("mongoContainer", {
2022-02-24 15:38:32 -08:00
image: mongoImage.repoDigest,
2022-02-10 08:46:56 -08:00
name: `mongo-${stack}` ,
ports: [
{
internal: mongoPort,
external: mongoPort,
},
],
networksAdvanced: [
{
name: network.name,
aliases: ["mongo"],
},
],
});
```
{{% /choosable %}}
2021-11-08 16:04:20 -06:00
{{% choosable language python %}}
```python
2022-12-19 10:14:04 -07:00
# Create the MongoDB container
2021-11-08 16:04:20 -06:00
mongo_container = docker.Container("mongo_container",
2022-02-24 15:38:32 -08:00
image=mongo_image.repo_digest,
2021-11-08 16:04:20 -06:00
name=f"mongo-{stack}",
ports=[docker.ContainerPortArgs(
internal=mongo_port,
external=mongo_port
)],
networks_advanced=[docker.ContainerNetworksAdvancedArgs(
name=network.name,
aliases=["mongo"]
)]
)
```
{{% /choosable %}}
2022-12-19 10:14:04 -07:00
{{% choosable language go %}}
```go
// Create the MongoDB container
mongoContainer, err := docker.NewContainer(ctx, "mongo-container", & docker.ContainerArgs{
Name: pulumi.String(fmt.Sprintf("mongo-%v", ctx.Stack())),
Image: mongoImage.RepoDigest,
Ports: & docker.ContainerPortArray{
& docker.ContainerPortArgs{
Internal: pulumi.Int(mongoPort),
External: pulumi.Int(mongoPort),
},
},
NetworksAdvanced: & docker.ContainerNetworksAdvancedArray{
& docker.ContainerNetworksAdvancedArgs{
Name: network.Name,
Aliases: pulumi.StringArray{
pulumi.String("mongo"),
},
},
},
})
if err != nil {
return err
}
```
{{% /choosable %}}
2022-05-03 21:23:32 -07:00
{{% choosable language java %}}
```java
2022-12-19 10:14:04 -07:00
// Create the MongoDB container
2022-08-31 13:57:44 -05:00
final var mongoContainer = new Container(
2022-05-03 21:23:32 -07:00
"mongoContainer",
ContainerArgs.builder()
.name(String.format("mongo-%s",stackName))
.image(mongoImage.repoDigest())
.ports(ContainerPortArgs.builder()
.internal(mongoPort)
.external(mongoPort)
.build())
.networksAdvanced(ContainerNetworksAdvancedArgs.builder()
.name(network.name())
.aliases("mongo")
.build()
)
.build()
);
```
{{% /choosable %}}
{{% choosable language yaml %}}
```yaml
2022-12-19 10:14:04 -07:00
# Create the MongoDB container
mongo-container:
type: docker:index:Container
properties:
name: mongo-${pulumi.stack}
image: ${mongo-image.repoDigest}
ports:
- internal: ${mongoPort}
external: ${mongoPort}
networksAdvanced:
- name: ${network.name}
aliases: ["mongo"]
2022-05-03 21:23:32 -07:00
```
{{% /choosable %}}
2021-11-08 16:04:20 -06:00
And the code for the frontend container:
2022-12-19 10:14:04 -07:00
{{< chooser language " typescript , python , go , java , yaml " / > }}
2022-02-10 08:46:56 -08:00
{{% choosable language typescript %}}
```typescript
2022-12-19 10:14:04 -07:00
// Create the frontend container
2022-02-10 08:46:56 -08:00
const frontendContainer = new docker.Container("frontendContainer", {
2022-05-03 21:23:32 -07:00
image: frontend.repoDigest,
2022-02-10 08:46:56 -08:00
name: `frontend-${stack}` ,
ports: [
{
internal: frontendPort,
external: frontendPort,
},
],
envs: [
2023-01-12 10:51:55 -08:00
`PORT=${frontendPort}` ,
2022-02-10 08:46:56 -08:00
`HTTP_PROXY=backend-${stack}:${backendPort}` ,
2022-05-03 21:23:32 -07:00
`PROXY_PROTOCOL=${protocol}`
2022-02-10 08:46:56 -08:00
],
networksAdvanced: [
{
name: network.name,
},
],
});
```
{{% /choosable %}}
2021-11-08 16:04:20 -06:00
{{% choosable language python %}}
```python
2022-12-19 10:14:04 -07:00
# Create the frontend container
2021-11-08 16:04:20 -06:00
frontend_container = docker.Container("frontend_container",
2022-05-03 21:23:32 -07:00
image=frontend.repo_digest,
2021-11-08 16:04:20 -06:00
name=f"frontend-{stack}",
ports=[docker.ContainerPortArgs(
internal=frontend_port,
external=frontend_port
)],
envs=[
2023-01-12 10:51:55 -08:00
f"PORT={frontend_port}",
2022-05-03 21:23:32 -07:00
f"HTTP_PROXY=backend-{stack}:{backend_port}",
f"PROXY_PROTOCOL={protocol}"
2021-11-08 16:04:20 -06:00
],
networks_advanced=[docker.ContainerNetworksAdvancedArgs(
name=network.name
)]
)
```
{{% /choosable %}}
2022-12-19 10:14:04 -07:00
{{% choosable language go %}}
```go
// Create the frontend container
_, err = docker.NewContainer(ctx, "frontend-container", & docker.ContainerArgs{
Name: pulumi.String(fmt.Sprintf("frontend-%v", ctx.Stack())),
Image: frontendImage.RepoDigest,
Ports: & docker.ContainerPortArray{
& docker.ContainerPortArgs{
Internal: pulumi.Int(frontendPort),
External: pulumi.Int(frontendPort),
},
},
Envs: pulumi.StringArray{
2023-01-12 10:51:55 -08:00
pulumi.String(fmt.Sprintf("PORT=%v", frontendPort)),
2022-12-19 10:14:04 -07:00
pulumi.String(fmt.Sprintf("HTTP_PROXY=backend-%v:%v", ctx.Stack(), backendPort)),
pulumi.String(fmt.Sprintf("PROXY_PROTOCOL=%v", protocol)),
},
NetworksAdvanced: & docker.ContainerNetworksAdvancedArray{
& docker.ContainerNetworksAdvancedArgs{
Name: network.Name,
Aliases: pulumi.StringArray{
pulumi.String(fmt.Sprintf("frontend-%v", ctx.Stack())),
},
},
},
})
if err != nil {
return err
}
```
At this point, all the variables we've declared have been used, so you can remove all the `ctx.Export` statements, and remove this line from the configuration declarations near the top of your program:
```go
_ = frontendPort + backendPort + mongoPort
```
We used these lines to temporarily satisfy Go's requirements as we were building out the program; now that our program is complete, they are no longer needed.
{{% /choosable %}}
2022-05-03 21:23:32 -07:00
{{% choosable language java %}}
```java
2022-12-19 10:14:04 -07:00
// Create the frontend container
2022-08-31 13:57:44 -05:00
final var frontendContainer = new Container(
2022-05-03 21:23:32 -07:00
"frontendContainer",
ContainerArgs.builder()
.name(String.format("frontend-%s",stackName))
.image(frontendImage.repoDigest())
.ports(ContainerPortArgs.builder()
.internal(frontendPort)
.external(frontendPort)
.build())
.envs(List.of(
2023-01-12 10:51:55 -08:00
String.format("PORT=%d",frontendPort),
2022-05-03 21:23:32 -07:00
String.format("HTTP_PROXY=backend-%s:%d",stackName,backendPort),
String.format("PROXY_PROTOCOL=%s",protocol)
))
.networksAdvanced(ContainerNetworksAdvancedArgs.builder()
.name(network.name())
.build())
.build()
);
```
{{% /choosable %}}
{{% choosable language yaml %}}
```yaml
2022-12-19 10:14:04 -07:00
# Create the frontend container
frontend-container:
type: docker:index:Container
properties:
name: ${frontendImageName}-${pulumi.stack}
image: ${frontend-image.repoDigest}
ports:
- internal: ${frontendPort}
external: ${frontendPort}
envs:
[
2023-01-12 10:51:55 -08:00
"PORT=${frontendPort}",
2022-12-19 10:14:04 -07:00
"HTTP_PROXY=backend-${pulumi.stack}:${backendPort}",
"PROXY_PROTOCOL=${protocol}"
]
networksAdvanced:
- name: ${network.name}
aliases: ["${frontendImageName}-${pulumi.stack}"]
2022-05-03 21:23:32 -07:00
```
{{% /choosable %}}
2021-11-08 16:04:20 -06:00
Let's see what the whole program looks like next.
## Put it all together
Now that we know how to create a container we can complete our program.
2022-12-19 10:14:04 -07:00
{{< chooser language " typescript , python , go , java , yaml " / > }}
2022-02-10 08:46:56 -08:00
{{% choosable language typescript %}}
```typescript
import * as pulumi from "@pulumi/pulumi ";
import * as docker from "@pulumi/docker ";
2022-12-19 10:14:04 -07:00
// Get configuration values
2022-02-10 08:46:56 -08:00
const config = new pulumi.Config();
2022-05-03 21:23:32 -07:00
const frontendPort = config.requireNumber("frontendPort");
const backendPort = config.requireNumber("backendPort");
const mongoPort = config.requireNumber("mongoPort");
const mongoHost = config.require("mongoHost"); // Note that strings are the default, so it's not `config.requireString` , just `config.require` .
2022-02-10 08:46:56 -08:00
const database = config.require("database");
2022-05-03 21:23:32 -07:00
const nodeEnvironment = config.require("nodeEnvironment");
const protocol = config.require("protocol")
2022-02-10 08:46:56 -08:00
const stack = pulumi.getStack();
2022-12-19 10:14:04 -07:00
// Pull the backend image
2022-02-10 08:46:56 -08:00
const backendImageName = "backend";
2022-12-19 10:14:04 -07:00
const backend = new docker.RemoteImage(`${backendImageName}Image` , {
2022-05-03 21:23:32 -07:00
name: "pulumi/tutorial-pulumi-fundamentals-backend:latest",
2022-02-10 08:46:56 -08:00
});
2022-12-19 10:14:04 -07:00
// Pull the frontend image
2022-02-10 08:46:56 -08:00
const frontendImageName = "frontend";
2022-12-19 10:14:04 -07:00
const frontend = new docker.RemoteImage(`${frontendImageName}Image` , {
2022-05-03 21:23:32 -07:00
name: "pulumi/tutorial-pulumi-fundamentals-frontend:latest",
2022-02-10 08:46:56 -08:00
});
2022-12-19 10:14:04 -07:00
// Pull the MongoDB image
const mongoImage = new docker.RemoteImage("mongoImage", {
2022-05-03 21:23:32 -07:00
name: "pulumi/tutorial-pulumi-fundamentals-database-local:latest",
2022-02-10 08:46:56 -08:00
});
2022-12-19 10:14:04 -07:00
// Create a Docker network
2022-02-10 08:46:56 -08:00
const network = new docker.Network("network", {
name: `services-${stack}` ,
});
2022-12-19 10:14:04 -07:00
// Create the MongoDB container
2022-02-10 08:46:56 -08:00
const mongoContainer = new docker.Container("mongoContainer", {
2022-02-24 15:38:32 -08:00
image: mongoImage.repoDigest,
2022-02-10 08:46:56 -08:00
name: `mongo-${stack}` ,
ports: [
{
internal: mongoPort,
external: mongoPort,
},
],
networksAdvanced: [
{
name: network.name,
aliases: ["mongo"],
},
],
});
2022-12-19 10:14:04 -07:00
// Create the backend container
2022-02-10 08:46:56 -08:00
const backendContainer = new docker.Container("backendContainer", {
name: `backend-${stack}` ,
2022-05-03 21:23:32 -07:00
image: backend.repoDigest,
2022-02-10 08:46:56 -08:00
ports: [
{
internal: backendPort,
external: backendPort,
},
],
envs: [
`DATABASE_HOST=${mongoHost}` ,
`DATABASE_NAME=${database}` ,
`NODE_ENV=${nodeEnvironment}` ,
],
networksAdvanced: [
{
name: network.name,
},
],
}, { dependsOn: [ mongoContainer ]});
2022-12-19 10:14:04 -07:00
// Create the frontend container
2022-02-10 08:46:56 -08:00
const frontendContainer = new docker.Container("frontendContainer", {
2022-05-03 21:23:32 -07:00
image: frontend.repoDigest,
2022-02-10 08:46:56 -08:00
name: `frontend-${stack}` ,
ports: [
{
internal: frontendPort,
external: frontendPort,
},
],
envs: [
2023-01-12 10:51:55 -08:00
`PORT=${frontendPort}` ,
2022-02-10 08:46:56 -08:00
`HTTP_PROXY=backend-${stack}:${backendPort}` ,
2022-05-03 21:23:32 -07:00
`PROXY_PROTOCOL=${protocol}`
2022-02-10 08:46:56 -08:00
],
networksAdvanced: [
{
name: network.name,
},
],
});
```
{{% /choosable %}}
2021-11-08 16:04:20 -06:00
{{% choosable language python %}}
```python
import pulumi
import pulumi_docker as docker
2022-12-19 10:14:04 -07:00
# Get configuration values
2021-11-08 16:04:20 -06:00
config = pulumi.Config()
2022-05-03 21:23:32 -07:00
frontend_port = config.require_int("frontendPort")
backend_port = config.require_int("backendPort")
mongo_port = config.require_int("mongoPort")
mongo_host = config.require("mongoHost") # Note that strings are the default, so it's not `config.require_str` , just `config.require` .
2021-11-08 16:04:20 -06:00
database = config.require("database")
2022-05-03 21:23:32 -07:00
node_environment = config.require("nodeEnvironment")
protocol = config.require("protocol")
2021-11-08 16:04:20 -06:00
2022-02-24 15:38:32 -08:00
stack = pulumi.get_stack()
2022-12-19 10:14:04 -07:00
# Pull the backend image
2021-11-08 16:04:20 -06:00
backend_image_name = "backend"
2022-12-19 10:14:04 -07:00
backend = docker.RemoteImage(f"{backend_image_name}_image",
2022-05-03 21:23:32 -07:00
name="pulumi/tutorial-pulumi-fundamentals-backend:latest"
)
2021-11-08 16:04:20 -06:00
2022-12-19 10:14:04 -07:00
# Pull the frontend image
2021-11-08 16:04:20 -06:00
frontend_image_name = "frontend"
2022-12-19 10:14:04 -07:00
frontend = docker.RemoteImage(f"{frontend_image_name}_image",
2022-05-03 21:23:32 -07:00
name="pulumi/tutorial-pulumi-fundamentals-frontend:latest"
)
2021-11-08 16:04:20 -06:00
2022-12-19 10:14:04 -07:00
# Pull the MongoDB image
mongo_image = docker.RemoteImage("mongo_image",
2022-05-03 21:23:32 -07:00
name="pulumi/tutorial-pulumi-fundamentals-database-local:latest"
)
2021-11-08 16:04:20 -06:00
2022-12-19 10:14:04 -07:00
# Create a Docker network
network = docker.Network("network", name=f"services_{stack}")
2021-11-08 16:04:20 -06:00
2022-12-19 10:14:04 -07:00
# Create the MongoDB container
2021-11-08 16:04:20 -06:00
mongo_container = docker.Container("mongo_container",
2022-02-24 15:38:32 -08:00
image=mongo_image.repo_digest,
name=f"mongo-{stack}",
ports=[docker.ContainerPortArgs(
internal=mongo_port,
external=mongo_port
)],
networks_advanced=[docker.ContainerNetworksAdvancedArgs(
name=network.name,
aliases=["mongo"]
)]
)
2021-11-08 16:04:20 -06:00
2022-12-19 10:14:04 -07:00
# Create the backend container
2021-11-08 16:04:20 -06:00
backend_container = docker.Container("backend_container",
2022-02-24 15:38:32 -08:00
name=f"backend-{stack}",
2022-05-03 21:23:32 -07:00
image=backend.repo_digest,
2022-02-24 15:38:32 -08:00
ports=[docker.ContainerPortArgs(
internal=backend_port,
external=backend_port)],
envs=[
f"DATABASE_HOST={mongo_host}",
f"DATABASE_NAME={database}",
f"NODE_ENV={node_environment}"
],
networks_advanced=[docker.ContainerNetworksAdvancedArgs(
name=network.name
)],
opts=pulumi.ResourceOptions(depends_on=[mongo_container])
)
2021-11-08 16:04:20 -06:00
2022-12-19 10:14:04 -07:00
# Create the frontend container
2021-11-08 16:04:20 -06:00
frontend_container = docker.Container("frontend_container",
2022-05-03 21:23:32 -07:00
image=frontend.repo_digest,
2021-11-08 16:04:20 -06:00
name=f"frontend-{stack}",
ports=[docker.ContainerPortArgs(
internal=frontend_port,
external=frontend_port
)],
envs=[
2023-01-12 10:51:55 -08:00
f"PORT={frontend_port}",
2022-05-03 21:23:32 -07:00
f"HTTP_PROXY=backend-{stack}:{backend_port}",
f"PROXY_PROTOCOL={protocol}"
2021-11-08 16:04:20 -06:00
],
networks_advanced=[docker.ContainerNetworksAdvancedArgs(
name=network.name
)]
)
2022-02-24 15:38:32 -08:00
2021-11-08 16:04:20 -06:00
```
{{% /choosable %}}
2022-12-19 10:14:04 -07:00
{{% choosable language go %}}
```go
package main
import (
"fmt"
"github.com/pulumi/pulumi-docker/sdk/v3/go/docker"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
// Get configuration values
cfg := config.New(ctx, "")
frontendPort := cfg.RequireFloat64("frontendPort")
backendPort := cfg.RequireFloat64("backendPort")
mongoPort := cfg.RequireFloat64("mongoPort")
mongoHost := cfg.Require("mongoHost") // Note that strings are the default, so it's not `cfg.RequireStr` , just `cfg.Require`
database := cfg.Require("database")
nodeEnvironment := cfg.Require("nodeEnvironment")
protocol := cfg.Require("protocol")
// Pull the backend image
backendImageName := "backend"
backendImage, err := docker.NewRemoteImage(ctx, fmt.Sprintf("%v-image", backendImageName), & docker.RemoteImageArgs{
Name: pulumi.String("pulumi/tutorial-pulumi-fundamentals-backend:latest"),
})
if err != nil {
return err
}
// Pull the frontend image
frontendImageName := "frontend"
frontendImage, err := docker.NewRemoteImage(ctx, fmt.Sprintf("%v-image", frontendImageName), & docker.RemoteImageArgs{
Name: pulumi.String("pulumi/tutorial-pulumi-fundamentals-frontend:latest"),
})
if err != nil {
return err
}
// Pull the MongoDB image
mongoImage, err := docker.NewRemoteImage(ctx, "mongo-image", & docker.RemoteImageArgs{
Name: pulumi.String("pulumi/tutorial-pulumi-fundamentals-database-local:latest"),
})
if err != nil {
return err
}
// Create a Docker network
network, err := docker.NewNetwork(ctx, "network", & docker.NetworkArgs{
Name: pulumi.String(fmt.Sprintf("services-%v", ctx.Stack())),
})
if err != nil {
return err
}
// Create the MongoDB container
mongoContainer, err := docker.NewContainer(ctx, "mongo-container", & docker.ContainerArgs{
Name: pulumi.String(fmt.Sprintf("mongo-%v", ctx.Stack())),
Image: mongoImage.RepoDigest,
Ports: & docker.ContainerPortArray{
& docker.ContainerPortArgs{
Internal: pulumi.Int(mongoPort),
External: pulumi.Int(mongoPort),
},
},
NetworksAdvanced: & docker.ContainerNetworksAdvancedArray{
& docker.ContainerNetworksAdvancedArgs{
Name: network.Name,
Aliases: pulumi.StringArray{
pulumi.String("mongo"),
},
},
},
})
if err != nil {
return err
}
// Create the backend container
// Use _ instead of a variable name since this container isn't referenced
_, err = docker.NewContainer(ctx, "backend-container", & docker.ContainerArgs{
Name: pulumi.String(fmt.Sprintf("backend-%v", ctx.Stack())),
Image: backendImage.RepoDigest,
Ports: & docker.ContainerPortArray{
& docker.ContainerPortArgs{
Internal: pulumi.Int(backendPort),
External: pulumi.Int(backendPort),
},
},
Envs: pulumi.StringArray{
pulumi.String(fmt.Sprintf("DATABASE_HOST=%v", mongoHost)),
pulumi.String(fmt.Sprintf("DATABASE_NAME=%v", database)),
pulumi.String(fmt.Sprintf("NODE_ENV=%v", nodeEnvironment)),
},
NetworksAdvanced: & docker.ContainerNetworksAdvancedArray{
& docker.ContainerNetworksAdvancedArgs{
Name: network.Name,
Aliases: pulumi.StringArray{
pulumi.String(fmt.Sprintf("backend-%v", ctx.Stack())),
},
},
},
}, pulumi.DependsOn([]pulumi.Resource{
mongoContainer,
}))
if err != nil {
return err
}
// Create a frontend container
_, err = docker.NewContainer(ctx, "frontend-container", & docker.ContainerArgs{
Name: pulumi.String(fmt.Sprintf("frontend-%v", ctx.Stack())),
Image: frontendImage.RepoDigest,
Ports: & docker.ContainerPortArray{
& docker.ContainerPortArgs{
Internal: pulumi.Int(frontendPort),
External: pulumi.Int(frontendPort),
},
},
Envs: pulumi.StringArray{
2023-01-12 10:51:55 -08:00
pulumi.String(fmt.Sprintf("PORT=%v", frontendPort)),
2022-12-19 10:14:04 -07:00
pulumi.String(fmt.Sprintf("HTTP_PROXY=backend-%v:%v", ctx.Stack(), backendPort)),
pulumi.String(fmt.Sprintf("PROXY_PROTOCOL=%v", protocol)),
},
NetworksAdvanced: & docker.ContainerNetworksAdvancedArray{
& docker.ContainerNetworksAdvancedArgs{
Name: network.Name,
Aliases: pulumi.StringArray{
pulumi.String(fmt.Sprintf("frontend-%v", ctx.Stack())),
},
},
},
})
if err != nil {
return err
}
return nil
})
}
```
{{% /choosable %}}
2022-05-03 21:23:32 -07:00
{{% choosable language java %}}
```java
package my_first_app;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.docker.RemoteImage;
import com.pulumi.docker.RemoteImageArgs;
import com.pulumi.docker.Network;
import com.pulumi.docker.NetworkArgs;
import com.pulumi.docker.Container;
import com.pulumi.docker.ContainerArgs;
import com.pulumi.docker.inputs.ContainerNetworksAdvancedArgs;
import com.pulumi.docker.inputs.ContainerPortArgs;
import com.pulumi.resources.CustomResourceOptions;
import java.util.List;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
2022-05-05 14:18:45 -05:00
private static void stack(Context ctx) {
2022-12-19 10:14:04 -07:00
// Get configuration values
2022-08-31 13:57:44 -05:00
final var config = ctx.config();
final var frontendPort = config.requireInteger("frontendPort");
final var backendPort = config.requireInteger("backendPort");
final var mongoPort = config.requireInteger("mongoPort");
final var mongoHost = config.require("mongoHost");
final var database = config.require("database");
final var nodeEnvironment = config.require("nodeEnvironment");
final var protocol = config.require("protocol");
2022-05-03 21:23:32 -07:00
final var stackName = ctx.stackName();
2022-12-19 10:14:04 -07:00
// Create the backend image
2022-05-03 21:23:32 -07:00
final String backendImageName = "backend";
2022-08-31 13:57:44 -05:00
final var backendImage = new RemoteImage(
2022-05-03 21:23:32 -07:00
backendImageName,
RemoteImageArgs.builder()
.name(String.format("pulumi/tutorial-pulumi-fundamentals-%s:latest",backendImageName))
.build()
);
2022-12-19 10:14:04 -07:00
// Create the frontend image
2022-05-03 21:23:32 -07:00
final String frontendImageName = "frontend";
2022-08-31 13:57:44 -05:00
final var frontendImage = new RemoteImage(
2022-05-03 21:23:32 -07:00
frontendImageName,
RemoteImageArgs.builder()
.name(String.format("pulumi/tutorial-pulumi-fundamentals-%s:latest",frontendImageName))
.build()
);
2022-12-19 10:14:04 -07:00
// Create the MongoDB image
2022-08-31 13:57:44 -05:00
final var mongoImage = new RemoteImage(
2022-05-03 21:23:32 -07:00
"mongoImage",
RemoteImageArgs.builder()
.name("pulumi/tutorial-pulumi-fundamentals-database-local:latest")
.build()
);
2022-12-19 10:14:04 -07:00
// Create a Docker network
2022-08-31 13:57:44 -05:00
final var network = new Network(
2022-05-03 21:23:32 -07:00
"network",
NetworkArgs.builder()
.name(String.format("services-%s",stackName))
.build()
);
2022-12-19 10:14:04 -07:00
// Create the MongoDB container
2022-08-31 13:57:44 -05:00
final var mongoContainer = new Container(
2022-05-03 21:23:32 -07:00
"mongoContainer",
ContainerArgs.builder()
.name(String.format("mongo-%s",stackName))
.image(mongoImage.repoDigest())
.ports(ContainerPortArgs.builder()
.internal(mongoPort)
.external(mongoPort)
.build())
.networksAdvanced(ContainerNetworksAdvancedArgs.builder()
.name(network.name())
.aliases("mongo")
.build()
)
.build()
);
2022-12-19 10:14:04 -07:00
// Create the backend container
2022-08-31 13:57:44 -05:00
final var backendContainer = new Container(
2022-05-03 21:23:32 -07:00
"backendContainer",
ContainerArgs.builder()
.name(String.format("backend-%s",stackName))
.image(backendImage.repoDigest())
.ports(ContainerPortArgs.builder()
.internal(backendPort)
.external(backendPort)
.build())
.envs(List.of(
String.format("DATABASE_HOST=%s",mongoHost),
String.format("DATABASE_NAME=%s",database),
2022-07-13 11:16:30 -06:00
String.format("NODE_ENV=%s",nodeEnvironment)
2022-05-03 21:23:32 -07:00
))
.networksAdvanced(ContainerNetworksAdvancedArgs.builder()
.name(network.name())
.build()
)
.build(),
CustomResourceOptions.builder()
.dependsOn(mongoContainer)
.build()
);
2022-12-19 10:14:04 -07:00
// Create the frontend container
2022-08-31 13:57:44 -05:00
final var frontendContainer = new Container(
2022-05-03 21:23:32 -07:00
"frontendContainer",
ContainerArgs.builder()
.name(String.format("frontend-%s",stackName))
.image(frontendImage.repoDigest())
.ports(ContainerPortArgs.builder()
.internal(frontendPort)
.external(frontendPort)
.build()
)
.envs(List.of(
2023-01-12 10:51:55 -08:00
String.format("PORT=%d",frontendPort),
2022-05-03 21:23:32 -07:00
String.format("HTTP_PROXY=backend-%s:%d",stackName,backendPort),
String.format("PROXY_PROTOCOL=%s",protocol)
))
.networksAdvanced(ContainerNetworksAdvancedArgs.builder()
.name(network.name())
.build())
.build()
);
ctx.export("link", Output.of("http://localhost:3001"));
}
}
```
2021-11-08 16:04:20 -06:00
2022-05-03 21:23:32 -07:00
{{% /choosable %}}
2021-11-08 16:04:20 -06:00
2022-05-03 21:23:32 -07:00
{{% choosable language yaml %}}
```yaml
2022-09-01 10:35:26 -05:00
name: my_first_app
2022-05-03 21:23:32 -07:00
runtime: yaml
2022-09-01 10:35:26 -05:00
description: A minimal Pulumi YAML program
2022-12-19 10:14:04 -07:00
# Get configuration values
2022-05-03 21:23:32 -07:00
configuration:
frontendPort:
type: Number
backendPort:
type: Number
mongoPort:
type: Number
mongoHost:
type: String
database:
type: String
nodeEnvironment:
type: String
protocol:
type: String
2022-12-19 10:14:04 -07:00
# Define variables
2022-05-03 21:23:32 -07:00
variables:
backendImageName: backend
frontendImageName: frontend
2022-12-19 10:14:04 -07:00
2022-05-03 21:23:32 -07:00
resources:
2022-12-19 10:14:04 -07:00
# Pull the backend image
2022-05-03 21:23:32 -07:00
backend-image:
type: docker:index:RemoteImage
properties:
name: pulumi/tutorial-pulumi-fundamentals-backend:latest
2022-12-19 10:14:04 -07:00
# Pull the frontend image
2022-05-03 21:23:32 -07:00
frontend-image:
type: docker:index:RemoteImage
properties:
name: pulumi/tutorial-pulumi-fundamentals-frontend:latest
2022-12-19 10:14:04 -07:00
# Pull the MongoDB image
2022-05-03 21:23:32 -07:00
mongo-image:
type: docker:index:RemoteImage
properties:
name: pulumi/tutorial-pulumi-fundamentals-database-local:latest
2022-12-19 10:14:04 -07:00
# Create a Docker network
2022-05-03 21:23:32 -07:00
network:
type: docker:index:Network
properties:
name: services-${pulumi.stack}
2022-12-19 10:14:04 -07:00
# Create the MongoDB container
mongo-container:
type: docker:index:Container
properties:
name: mongo-${pulumi.stack}
image: ${mongo-image.repoDigest}
ports:
- internal: ${mongoPort}
external: ${mongoPort}
networksAdvanced:
- name: ${network.name}
aliases: ["mongo"]
# Create the backend container
2022-05-03 21:23:32 -07:00
backend-container:
type: docker:index:Container
properties:
2022-09-01 10:35:26 -05:00
name: ${backendImageName}-${pulumi.stack}
2022-05-03 21:23:32 -07:00
image: ${backend-image.repoDigest}
ports:
- internal: ${backendPort}
external: ${backendPort}
envs:
[
"DATABASE_HOST=${mongoHost}",
"DATABASE_NAME=${database}",
"NODE_ENV=${nodeEnvironment}"
]
networksAdvanced:
- name: ${network.name}
2022-09-01 10:35:26 -05:00
aliases: ["${backendImageName}-${pulumi.stack}"]
2022-05-03 21:23:32 -07:00
options:
dependsOn:
- ${mongo-container}
2022-12-19 10:14:04 -07:00
# Create the frontend container
2022-05-03 21:23:32 -07:00
frontend-container:
type: docker:index:Container
properties:
2022-09-01 10:35:26 -05:00
name: ${frontendImageName}-${pulumi.stack}
2022-05-03 21:23:32 -07:00
image: ${frontend-image.repoDigest}
ports:
- internal: ${frontendPort}
external: ${frontendPort}
envs:
[
2023-01-12 10:51:55 -08:00
"PORT=${frontendPort}",
2022-05-03 21:23:32 -07:00
"HTTP_PROXY=backend-${pulumi.stack}:${backendPort}",
2022-09-01 10:35:26 -05:00
"PROXY_PROTOCOL=${protocol}"
2022-05-03 21:23:32 -07:00
]
networksAdvanced:
- name: ${network.name}
2022-09-01 10:35:26 -05:00
aliases: ["${frontendImageName}-${pulumi.stack}"]
outputs: {}
2022-05-03 21:23:32 -07:00
```
2021-11-08 16:04:20 -06:00
2022-05-03 21:23:32 -07:00
{{% /choosable %}}
2021-11-08 16:04:20 -06:00
2022-05-03 21:23:32 -07:00
With Docker networking, we can use image names to refer to a container. In our
example, the React frontend client sends requests to the Express backend client.
The URL to the backend is set via the `setupProxy.js` file in the
`app/frontend/src` directory with the `HTTP_PROXY` environment variable.
2021-11-08 16:04:20 -06:00
2022-05-03 21:23:32 -07:00
Run `pulumi up` to get the application running. Open a browser to `http://localhost:3001` , and our application is now deployed.
2021-11-08 16:04:20 -06:00
2022-05-03 21:23:32 -07:00
## Update the database
2021-11-08 16:04:20 -06:00
2022-05-03 21:23:32 -07:00
What if we want to add to the products on the page? We can POST to the API just as we would any API. Generally speaking, you would typically wire the database to an API and update it that way with any cloud, so we're going to do exactly that here.
2022-02-10 08:46:56 -08:00
2022-05-03 21:23:32 -07:00
Open a terminal and run the following command.
2022-02-10 08:46:56 -08:00
2022-05-03 21:23:32 -07:00
```bash
curl --location --request POST 'http://localhost:3000/api/products' \
--header 'Content-Type: application/json' \
--data-raw '{
"ratings": {
"reviews": [],
"total": 63,
"avg": 5
},
"created": 1600979464567,
"currency": {
"id": "USD",
"format": "$"
},
"sizes": [
"M",
"L"
2022-02-10 08:46:56 -08:00
],
2022-05-03 21:23:32 -07:00
"category": "boba",
"teaType": 2,
"status": 1,
"_id": "5f6d025008a1b6f0e5636bc7",
"images": [
2022-02-10 08:46:56 -08:00
{
2022-05-03 21:23:32 -07:00
"src": "classic_boba.png"
}
2022-02-10 08:46:56 -08:00
],
2022-05-03 21:23:32 -07:00
"name": "My New Milk Tea",
"price": 5,
"description": "none",
"productCode": "852542-107"
}'
2022-02-10 08:46:56 -08:00
```
2022-05-03 21:23:32 -07:00
You should get back the following response:
2021-11-08 16:04:20 -06:00
2022-05-03 21:23:32 -07:00
```bash
{"status":"ok","data":{"product":{"ratings":{"reviews":[],"total":63,"avg":5},"created":1600979464567,"currency":{"id":"USD","format":"$"},"sizes":["M","L"],"category":"boba","teaType":2,"status":1,"_id":"5f6d025008a1b6f0e5636bc7","images":[{"_id":"62608f2a9ad5d90026847b0f","src":"classic_boba.png"}],"name":"My New Milk Tea","price":5,"description":"none","productCode":"852542-107","__v":0}}}
```
2021-11-08 16:04:20 -06:00
2022-05-03 21:23:32 -07:00
Refresh the app on `http://localhost:3001` , and our data is now updated!
2021-11-08 16:04:20 -06:00
## Cleaning up
Whenever you're working on learning something new with Pulumi, it's always a
good idea to clean up any resources you've created so you don't get charged on a
free tier or otherwise leave behind resources you'll never use. Let's clean up.
Run the `pulumi destroy` command to remove all of the resources:
```bash
$ pulumi destroy
Previewing destroy (dev)
View Live: https://app.pulumi.com/< org > /< project > /< stack > /previews/< build-id >
...
Do you want to perform this destroy? yes
Destroying (dev)
View Live: https://app.pulumi.com/< org > /< project > /< stack > /updates/< update-id >
...
The resources in the stack have been deleted, but the history and configuration associated with the stack are still maintained.
If you want to remove the stack completely, run 'pulumi stack rm dev'.
```
Now your resources should all be cleared! That last comment you see in the
output notes that the stack and all of the configuration and history will stay
2022-02-10 08:46:56 -08:00
in your dashboard on the Pulumi Service ([app.pulumi.com ](https://app.pulumi.com/ )). For now, that's okay. We'll talk
2021-11-08 16:04:20 -06:00
more about removing the project from your history in another pathway.
---
Congratulations, you've now finished Pulumi Fundamentals! You learned to create
a Pulumi project; work on your Pulumi program to build Docker images,
containers, and networks; and deploy the infrastructure locally with your first
resource provider. Now, head back to the main page and explore some other
tutorials to understand more about Pulumi. The best next step to take is to
2022-10-26 07:22:15 -07:00
explore the [Building with Pulumi ](/learn/building-with-pulumi/ ) pathway.