The aws:appmesh/virtualNode:VirtualNode resource, part of the Pulumi AWS provider, defines a virtual node in App Mesh: a logical pointer to a service instance with its discovery mechanism, listeners, and backend dependencies. This guide focuses on three capabilities: DNS and Cloud Map service discovery, health check configuration, and access logging.
Virtual nodes belong to a mesh and reference virtual services as backends. The examples are intentionally small. Combine them with your own mesh, virtual services, and routing configuration.
Register a node with DNS-based service discovery
Most App Mesh deployments start by defining virtual nodes that represent service instances, declaring which services they call and how clients discover them.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const serviceb1 = new aws.appmesh.VirtualNode("serviceb1", {
name: "serviceBv1",
meshName: simple.id,
spec: {
backends: [{
virtualService: {
virtualServiceName: "servicea.simpleapp.local",
},
}],
listeners: [{
portMapping: {
port: 8080,
protocol: "http",
},
}],
serviceDiscovery: {
dns: {
hostname: "serviceb.simpleapp.local",
},
},
},
});
import pulumi
import pulumi_aws as aws
serviceb1 = aws.appmesh.VirtualNode("serviceb1",
name="serviceBv1",
mesh_name=simple["id"],
spec={
"backends": [{
"virtual_service": {
"virtual_service_name": "servicea.simpleapp.local",
},
}],
"listeners": [{
"port_mapping": {
"port": 8080,
"protocol": "http",
},
}],
"service_discovery": {
"dns": {
"hostname": "serviceb.simpleapp.local",
},
},
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/appmesh"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := appmesh.NewVirtualNode(ctx, "serviceb1", &appmesh.VirtualNodeArgs{
Name: pulumi.String("serviceBv1"),
MeshName: pulumi.Any(simple.Id),
Spec: &appmesh.VirtualNodeSpecArgs{
Backends: appmesh.VirtualNodeSpecBackendArray{
&appmesh.VirtualNodeSpecBackendArgs{
VirtualService: &appmesh.VirtualNodeSpecBackendVirtualServiceArgs{
VirtualServiceName: pulumi.String("servicea.simpleapp.local"),
},
},
},
Listeners: appmesh.VirtualNodeSpecListenerArray{
&appmesh.VirtualNodeSpecListenerArgs{
PortMapping: &appmesh.VirtualNodeSpecListenerPortMappingArgs{
Port: pulumi.Int(8080),
Protocol: pulumi.String("http"),
},
},
},
ServiceDiscovery: &appmesh.VirtualNodeSpecServiceDiscoveryArgs{
Dns: &appmesh.VirtualNodeSpecServiceDiscoveryDnsArgs{
Hostname: pulumi.String("serviceb.simpleapp.local"),
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var serviceb1 = new Aws.AppMesh.VirtualNode("serviceb1", new()
{
Name = "serviceBv1",
MeshName = simple.Id,
Spec = new Aws.AppMesh.Inputs.VirtualNodeSpecArgs
{
Backends = new[]
{
new Aws.AppMesh.Inputs.VirtualNodeSpecBackendArgs
{
VirtualService = new Aws.AppMesh.Inputs.VirtualNodeSpecBackendVirtualServiceArgs
{
VirtualServiceName = "servicea.simpleapp.local",
},
},
},
Listeners = new[]
{
new Aws.AppMesh.Inputs.VirtualNodeSpecListenerArgs
{
PortMapping = new Aws.AppMesh.Inputs.VirtualNodeSpecListenerPortMappingArgs
{
Port = 8080,
Protocol = "http",
},
},
},
ServiceDiscovery = new Aws.AppMesh.Inputs.VirtualNodeSpecServiceDiscoveryArgs
{
Dns = new Aws.AppMesh.Inputs.VirtualNodeSpecServiceDiscoveryDnsArgs
{
Hostname = "serviceb.simpleapp.local",
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.appmesh.VirtualNode;
import com.pulumi.aws.appmesh.VirtualNodeArgs;
import com.pulumi.aws.appmesh.inputs.VirtualNodeSpecArgs;
import com.pulumi.aws.appmesh.inputs.VirtualNodeSpecServiceDiscoveryArgs;
import com.pulumi.aws.appmesh.inputs.VirtualNodeSpecServiceDiscoveryDnsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var serviceb1 = new VirtualNode("serviceb1", VirtualNodeArgs.builder()
.name("serviceBv1")
.meshName(simple.id())
.spec(VirtualNodeSpecArgs.builder()
.backends(VirtualNodeSpecBackendArgs.builder()
.virtualService(VirtualNodeSpecBackendVirtualServiceArgs.builder()
.virtualServiceName("servicea.simpleapp.local")
.build())
.build())
.listeners(VirtualNodeSpecListenerArgs.builder()
.portMapping(VirtualNodeSpecListenerPortMappingArgs.builder()
.port(8080)
.protocol("http")
.build())
.build())
.serviceDiscovery(VirtualNodeSpecServiceDiscoveryArgs.builder()
.dns(VirtualNodeSpecServiceDiscoveryDnsArgs.builder()
.hostname("serviceb.simpleapp.local")
.build())
.build())
.build())
.build());
}
}
resources:
serviceb1:
type: aws:appmesh:VirtualNode
properties:
name: serviceBv1
meshName: ${simple.id}
spec:
backends:
- virtualService:
virtualServiceName: servicea.simpleapp.local
listeners:
- portMapping:
port: 8080
protocol: http
serviceDiscovery:
dns:
hostname: serviceb.simpleapp.local
The spec defines the node’s behavior. The backends array lists virtual services this node calls; each backend references a virtual service by name. The listeners array defines ports this node accepts traffic on, with portMapping specifying the port and protocol. The serviceDiscovery block tells App Mesh how clients find this node; dns uses a hostname that resolves to service instances.
Use AWS Cloud Map for dynamic service discovery
When service instances register dynamically or need attribute-based routing, Cloud Map provides a registry that tracks instance metadata and health.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.servicediscovery.HttpNamespace("example", {name: "example-ns"});
const serviceb1 = new aws.appmesh.VirtualNode("serviceb1", {
name: "serviceBv1",
meshName: simple.id,
spec: {
backends: [{
virtualService: {
virtualServiceName: "servicea.simpleapp.local",
},
}],
listeners: [{
portMapping: {
port: 8080,
protocol: "http",
},
}],
serviceDiscovery: {
awsCloudMap: {
attributes: {
stack: "blue",
},
serviceName: "serviceb1",
namespaceName: example.name,
},
},
},
});
import pulumi
import pulumi_aws as aws
example = aws.servicediscovery.HttpNamespace("example", name="example-ns")
serviceb1 = aws.appmesh.VirtualNode("serviceb1",
name="serviceBv1",
mesh_name=simple["id"],
spec={
"backends": [{
"virtual_service": {
"virtual_service_name": "servicea.simpleapp.local",
},
}],
"listeners": [{
"port_mapping": {
"port": 8080,
"protocol": "http",
},
}],
"service_discovery": {
"aws_cloud_map": {
"attributes": {
"stack": "blue",
},
"service_name": "serviceb1",
"namespace_name": example.name,
},
},
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/appmesh"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/servicediscovery"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
example, err := servicediscovery.NewHttpNamespace(ctx, "example", &servicediscovery.HttpNamespaceArgs{
Name: pulumi.String("example-ns"),
})
if err != nil {
return err
}
_, err = appmesh.NewVirtualNode(ctx, "serviceb1", &appmesh.VirtualNodeArgs{
Name: pulumi.String("serviceBv1"),
MeshName: pulumi.Any(simple.Id),
Spec: &appmesh.VirtualNodeSpecArgs{
Backends: appmesh.VirtualNodeSpecBackendArray{
&appmesh.VirtualNodeSpecBackendArgs{
VirtualService: &appmesh.VirtualNodeSpecBackendVirtualServiceArgs{
VirtualServiceName: pulumi.String("servicea.simpleapp.local"),
},
},
},
Listeners: appmesh.VirtualNodeSpecListenerArray{
&appmesh.VirtualNodeSpecListenerArgs{
PortMapping: &appmesh.VirtualNodeSpecListenerPortMappingArgs{
Port: pulumi.Int(8080),
Protocol: pulumi.String("http"),
},
},
},
ServiceDiscovery: &appmesh.VirtualNodeSpecServiceDiscoveryArgs{
AwsCloudMap: &appmesh.VirtualNodeSpecServiceDiscoveryAwsCloudMapArgs{
Attributes: pulumi.StringMap{
"stack": pulumi.String("blue"),
},
ServiceName: pulumi.String("serviceb1"),
NamespaceName: example.Name,
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.ServiceDiscovery.HttpNamespace("example", new()
{
Name = "example-ns",
});
var serviceb1 = new Aws.AppMesh.VirtualNode("serviceb1", new()
{
Name = "serviceBv1",
MeshName = simple.Id,
Spec = new Aws.AppMesh.Inputs.VirtualNodeSpecArgs
{
Backends = new[]
{
new Aws.AppMesh.Inputs.VirtualNodeSpecBackendArgs
{
VirtualService = new Aws.AppMesh.Inputs.VirtualNodeSpecBackendVirtualServiceArgs
{
VirtualServiceName = "servicea.simpleapp.local",
},
},
},
Listeners = new[]
{
new Aws.AppMesh.Inputs.VirtualNodeSpecListenerArgs
{
PortMapping = new Aws.AppMesh.Inputs.VirtualNodeSpecListenerPortMappingArgs
{
Port = 8080,
Protocol = "http",
},
},
},
ServiceDiscovery = new Aws.AppMesh.Inputs.VirtualNodeSpecServiceDiscoveryArgs
{
AwsCloudMap = new Aws.AppMesh.Inputs.VirtualNodeSpecServiceDiscoveryAwsCloudMapArgs
{
Attributes =
{
{ "stack", "blue" },
},
ServiceName = "serviceb1",
NamespaceName = example.Name,
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.servicediscovery.HttpNamespace;
import com.pulumi.aws.servicediscovery.HttpNamespaceArgs;
import com.pulumi.aws.appmesh.VirtualNode;
import com.pulumi.aws.appmesh.VirtualNodeArgs;
import com.pulumi.aws.appmesh.inputs.VirtualNodeSpecArgs;
import com.pulumi.aws.appmesh.inputs.VirtualNodeSpecServiceDiscoveryArgs;
import com.pulumi.aws.appmesh.inputs.VirtualNodeSpecServiceDiscoveryAwsCloudMapArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var example = new HttpNamespace("example", HttpNamespaceArgs.builder()
.name("example-ns")
.build());
var serviceb1 = new VirtualNode("serviceb1", VirtualNodeArgs.builder()
.name("serviceBv1")
.meshName(simple.id())
.spec(VirtualNodeSpecArgs.builder()
.backends(VirtualNodeSpecBackendArgs.builder()
.virtualService(VirtualNodeSpecBackendVirtualServiceArgs.builder()
.virtualServiceName("servicea.simpleapp.local")
.build())
.build())
.listeners(VirtualNodeSpecListenerArgs.builder()
.portMapping(VirtualNodeSpecListenerPortMappingArgs.builder()
.port(8080)
.protocol("http")
.build())
.build())
.serviceDiscovery(VirtualNodeSpecServiceDiscoveryArgs.builder()
.awsCloudMap(VirtualNodeSpecServiceDiscoveryAwsCloudMapArgs.builder()
.attributes(Map.of("stack", "blue"))
.serviceName("serviceb1")
.namespaceName(example.name())
.build())
.build())
.build())
.build());
}
}
resources:
example:
type: aws:servicediscovery:HttpNamespace
properties:
name: example-ns
serviceb1:
type: aws:appmesh:VirtualNode
properties:
name: serviceBv1
meshName: ${simple.id}
spec:
backends:
- virtualService:
virtualServiceName: servicea.simpleapp.local
listeners:
- portMapping:
port: 8080
protocol: http
serviceDiscovery:
awsCloudMap:
attributes:
stack: blue
serviceName: serviceb1
namespaceName: ${example.name}
The awsCloudMap block replaces dns for dynamic discovery. The serviceName and namespaceName point to a Cloud Map service registration. The attributes map adds metadata (like “stack: blue”) that can be used for routing decisions or filtering.
Configure health checks for listener endpoints
Production deployments need health checks to detect when service instances become unhealthy and should be removed from load balancing.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const serviceb1 = new aws.appmesh.VirtualNode("serviceb1", {
name: "serviceBv1",
meshName: simple.id,
spec: {
backends: [{
virtualService: {
virtualServiceName: "servicea.simpleapp.local",
},
}],
listeners: [{
portMapping: {
port: 8080,
protocol: "http",
},
healthCheck: {
protocol: "http",
path: "/ping",
healthyThreshold: 2,
unhealthyThreshold: 2,
timeoutMillis: 2000,
intervalMillis: 5000,
},
}],
serviceDiscovery: {
dns: {
hostname: "serviceb.simpleapp.local",
},
},
},
});
import pulumi
import pulumi_aws as aws
serviceb1 = aws.appmesh.VirtualNode("serviceb1",
name="serviceBv1",
mesh_name=simple["id"],
spec={
"backends": [{
"virtual_service": {
"virtual_service_name": "servicea.simpleapp.local",
},
}],
"listeners": [{
"port_mapping": {
"port": 8080,
"protocol": "http",
},
"health_check": {
"protocol": "http",
"path": "/ping",
"healthy_threshold": 2,
"unhealthy_threshold": 2,
"timeout_millis": 2000,
"interval_millis": 5000,
},
}],
"service_discovery": {
"dns": {
"hostname": "serviceb.simpleapp.local",
},
},
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/appmesh"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := appmesh.NewVirtualNode(ctx, "serviceb1", &appmesh.VirtualNodeArgs{
Name: pulumi.String("serviceBv1"),
MeshName: pulumi.Any(simple.Id),
Spec: &appmesh.VirtualNodeSpecArgs{
Backends: appmesh.VirtualNodeSpecBackendArray{
&appmesh.VirtualNodeSpecBackendArgs{
VirtualService: &appmesh.VirtualNodeSpecBackendVirtualServiceArgs{
VirtualServiceName: pulumi.String("servicea.simpleapp.local"),
},
},
},
Listeners: appmesh.VirtualNodeSpecListenerArray{
&appmesh.VirtualNodeSpecListenerArgs{
PortMapping: &appmesh.VirtualNodeSpecListenerPortMappingArgs{
Port: pulumi.Int(8080),
Protocol: pulumi.String("http"),
},
HealthCheck: &appmesh.VirtualNodeSpecListenerHealthCheckArgs{
Protocol: pulumi.String("http"),
Path: pulumi.String("/ping"),
HealthyThreshold: pulumi.Int(2),
UnhealthyThreshold: pulumi.Int(2),
TimeoutMillis: pulumi.Int(2000),
IntervalMillis: pulumi.Int(5000),
},
},
},
ServiceDiscovery: &appmesh.VirtualNodeSpecServiceDiscoveryArgs{
Dns: &appmesh.VirtualNodeSpecServiceDiscoveryDnsArgs{
Hostname: pulumi.String("serviceb.simpleapp.local"),
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var serviceb1 = new Aws.AppMesh.VirtualNode("serviceb1", new()
{
Name = "serviceBv1",
MeshName = simple.Id,
Spec = new Aws.AppMesh.Inputs.VirtualNodeSpecArgs
{
Backends = new[]
{
new Aws.AppMesh.Inputs.VirtualNodeSpecBackendArgs
{
VirtualService = new Aws.AppMesh.Inputs.VirtualNodeSpecBackendVirtualServiceArgs
{
VirtualServiceName = "servicea.simpleapp.local",
},
},
},
Listeners = new[]
{
new Aws.AppMesh.Inputs.VirtualNodeSpecListenerArgs
{
PortMapping = new Aws.AppMesh.Inputs.VirtualNodeSpecListenerPortMappingArgs
{
Port = 8080,
Protocol = "http",
},
HealthCheck = new Aws.AppMesh.Inputs.VirtualNodeSpecListenerHealthCheckArgs
{
Protocol = "http",
Path = "/ping",
HealthyThreshold = 2,
UnhealthyThreshold = 2,
TimeoutMillis = 2000,
IntervalMillis = 5000,
},
},
},
ServiceDiscovery = new Aws.AppMesh.Inputs.VirtualNodeSpecServiceDiscoveryArgs
{
Dns = new Aws.AppMesh.Inputs.VirtualNodeSpecServiceDiscoveryDnsArgs
{
Hostname = "serviceb.simpleapp.local",
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.appmesh.VirtualNode;
import com.pulumi.aws.appmesh.VirtualNodeArgs;
import com.pulumi.aws.appmesh.inputs.VirtualNodeSpecArgs;
import com.pulumi.aws.appmesh.inputs.VirtualNodeSpecServiceDiscoveryArgs;
import com.pulumi.aws.appmesh.inputs.VirtualNodeSpecServiceDiscoveryDnsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var serviceb1 = new VirtualNode("serviceb1", VirtualNodeArgs.builder()
.name("serviceBv1")
.meshName(simple.id())
.spec(VirtualNodeSpecArgs.builder()
.backends(VirtualNodeSpecBackendArgs.builder()
.virtualService(VirtualNodeSpecBackendVirtualServiceArgs.builder()
.virtualServiceName("servicea.simpleapp.local")
.build())
.build())
.listeners(VirtualNodeSpecListenerArgs.builder()
.portMapping(VirtualNodeSpecListenerPortMappingArgs.builder()
.port(8080)
.protocol("http")
.build())
.healthCheck(VirtualNodeSpecListenerHealthCheckArgs.builder()
.protocol("http")
.path("/ping")
.healthyThreshold(2)
.unhealthyThreshold(2)
.timeoutMillis(2000)
.intervalMillis(5000)
.build())
.build())
.serviceDiscovery(VirtualNodeSpecServiceDiscoveryArgs.builder()
.dns(VirtualNodeSpecServiceDiscoveryDnsArgs.builder()
.hostname("serviceb.simpleapp.local")
.build())
.build())
.build())
.build());
}
}
resources:
serviceb1:
type: aws:appmesh:VirtualNode
properties:
name: serviceBv1
meshName: ${simple.id}
spec:
backends:
- virtualService:
virtualServiceName: servicea.simpleapp.local
listeners:
- portMapping:
port: 8080
protocol: http
healthCheck:
protocol: http
path: /ping
healthyThreshold: 2
unhealthyThreshold: 2
timeoutMillis: 2000
intervalMillis: 5000
serviceDiscovery:
dns:
hostname: serviceb.simpleapp.local
The healthCheck block inside listeners defines how App Mesh probes the service. The protocol and path specify the health endpoint (here, HTTP GET /ping). The healthyThreshold and unhealthyThreshold control how many consecutive checks must pass or fail before changing state. The timeoutMillis and intervalMillis control check timing.
Stream access logs to stdout for observability
Debugging and monitoring require visibility into request patterns. App Mesh can stream access logs to a file path, typically stdout for container-based deployments.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const serviceb1 = new aws.appmesh.VirtualNode("serviceb1", {
name: "serviceBv1",
meshName: simple.id,
spec: {
backends: [{
virtualService: {
virtualServiceName: "servicea.simpleapp.local",
},
}],
listeners: [{
portMapping: {
port: 8080,
protocol: "http",
},
}],
serviceDiscovery: {
dns: {
hostname: "serviceb.simpleapp.local",
},
},
logging: {
accessLog: {
file: {
path: "/dev/stdout",
},
},
},
},
});
import pulumi
import pulumi_aws as aws
serviceb1 = aws.appmesh.VirtualNode("serviceb1",
name="serviceBv1",
mesh_name=simple["id"],
spec={
"backends": [{
"virtual_service": {
"virtual_service_name": "servicea.simpleapp.local",
},
}],
"listeners": [{
"port_mapping": {
"port": 8080,
"protocol": "http",
},
}],
"service_discovery": {
"dns": {
"hostname": "serviceb.simpleapp.local",
},
},
"logging": {
"access_log": {
"file": {
"path": "/dev/stdout",
},
},
},
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/appmesh"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := appmesh.NewVirtualNode(ctx, "serviceb1", &appmesh.VirtualNodeArgs{
Name: pulumi.String("serviceBv1"),
MeshName: pulumi.Any(simple.Id),
Spec: &appmesh.VirtualNodeSpecArgs{
Backends: appmesh.VirtualNodeSpecBackendArray{
&appmesh.VirtualNodeSpecBackendArgs{
VirtualService: &appmesh.VirtualNodeSpecBackendVirtualServiceArgs{
VirtualServiceName: pulumi.String("servicea.simpleapp.local"),
},
},
},
Listeners: appmesh.VirtualNodeSpecListenerArray{
&appmesh.VirtualNodeSpecListenerArgs{
PortMapping: &appmesh.VirtualNodeSpecListenerPortMappingArgs{
Port: pulumi.Int(8080),
Protocol: pulumi.String("http"),
},
},
},
ServiceDiscovery: &appmesh.VirtualNodeSpecServiceDiscoveryArgs{
Dns: &appmesh.VirtualNodeSpecServiceDiscoveryDnsArgs{
Hostname: pulumi.String("serviceb.simpleapp.local"),
},
},
Logging: &appmesh.VirtualNodeSpecLoggingArgs{
AccessLog: &appmesh.VirtualNodeSpecLoggingAccessLogArgs{
File: &appmesh.VirtualNodeSpecLoggingAccessLogFileArgs{
Path: pulumi.String("/dev/stdout"),
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var serviceb1 = new Aws.AppMesh.VirtualNode("serviceb1", new()
{
Name = "serviceBv1",
MeshName = simple.Id,
Spec = new Aws.AppMesh.Inputs.VirtualNodeSpecArgs
{
Backends = new[]
{
new Aws.AppMesh.Inputs.VirtualNodeSpecBackendArgs
{
VirtualService = new Aws.AppMesh.Inputs.VirtualNodeSpecBackendVirtualServiceArgs
{
VirtualServiceName = "servicea.simpleapp.local",
},
},
},
Listeners = new[]
{
new Aws.AppMesh.Inputs.VirtualNodeSpecListenerArgs
{
PortMapping = new Aws.AppMesh.Inputs.VirtualNodeSpecListenerPortMappingArgs
{
Port = 8080,
Protocol = "http",
},
},
},
ServiceDiscovery = new Aws.AppMesh.Inputs.VirtualNodeSpecServiceDiscoveryArgs
{
Dns = new Aws.AppMesh.Inputs.VirtualNodeSpecServiceDiscoveryDnsArgs
{
Hostname = "serviceb.simpleapp.local",
},
},
Logging = new Aws.AppMesh.Inputs.VirtualNodeSpecLoggingArgs
{
AccessLog = new Aws.AppMesh.Inputs.VirtualNodeSpecLoggingAccessLogArgs
{
File = new Aws.AppMesh.Inputs.VirtualNodeSpecLoggingAccessLogFileArgs
{
Path = "/dev/stdout",
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.appmesh.VirtualNode;
import com.pulumi.aws.appmesh.VirtualNodeArgs;
import com.pulumi.aws.appmesh.inputs.VirtualNodeSpecArgs;
import com.pulumi.aws.appmesh.inputs.VirtualNodeSpecServiceDiscoveryArgs;
import com.pulumi.aws.appmesh.inputs.VirtualNodeSpecServiceDiscoveryDnsArgs;
import com.pulumi.aws.appmesh.inputs.VirtualNodeSpecLoggingArgs;
import com.pulumi.aws.appmesh.inputs.VirtualNodeSpecLoggingAccessLogArgs;
import com.pulumi.aws.appmesh.inputs.VirtualNodeSpecLoggingAccessLogFileArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var serviceb1 = new VirtualNode("serviceb1", VirtualNodeArgs.builder()
.name("serviceBv1")
.meshName(simple.id())
.spec(VirtualNodeSpecArgs.builder()
.backends(VirtualNodeSpecBackendArgs.builder()
.virtualService(VirtualNodeSpecBackendVirtualServiceArgs.builder()
.virtualServiceName("servicea.simpleapp.local")
.build())
.build())
.listeners(VirtualNodeSpecListenerArgs.builder()
.portMapping(VirtualNodeSpecListenerPortMappingArgs.builder()
.port(8080)
.protocol("http")
.build())
.build())
.serviceDiscovery(VirtualNodeSpecServiceDiscoveryArgs.builder()
.dns(VirtualNodeSpecServiceDiscoveryDnsArgs.builder()
.hostname("serviceb.simpleapp.local")
.build())
.build())
.logging(VirtualNodeSpecLoggingArgs.builder()
.accessLog(VirtualNodeSpecLoggingAccessLogArgs.builder()
.file(VirtualNodeSpecLoggingAccessLogFileArgs.builder()
.path("/dev/stdout")
.build())
.build())
.build())
.build())
.build());
}
}
resources:
serviceb1:
type: aws:appmesh:VirtualNode
properties:
name: serviceBv1
meshName: ${simple.id}
spec:
backends:
- virtualService:
virtualServiceName: servicea.simpleapp.local
listeners:
- portMapping:
port: 8080
protocol: http
serviceDiscovery:
dns:
hostname: serviceb.simpleapp.local
logging:
accessLog:
file:
path: /dev/stdout
The logging block enables access logs. The accessLog.file.path property specifies where logs are written; /dev/stdout sends them to standard output, where container runtimes can capture them for CloudWatch or other log aggregators.
Beyond these examples
These snippets focus on specific virtual node features: service discovery (DNS and Cloud Map), health checks and access logging, and backend service dependencies. They’re intentionally minimal rather than full service mesh deployments.
The examples reference pre-existing infrastructure such as App Mesh service meshes, virtual services for backend dependencies, and Cloud Map namespaces for Cloud Map discovery. They focus on configuring the virtual node rather than provisioning the entire mesh topology.
To keep things focused, common virtual node patterns are omitted, including:
- TLS configuration for encrypted communication
- Connection pool tuning (timeouts, max connections)
- Outlier detection for circuit breaking
- Retry policies and timeout configuration
These omissions are intentional: the goal is to illustrate how each virtual node feature is wired, not provide drop-in service mesh modules. See the App Mesh VirtualNode resource reference for all available configuration options.
Let's configure AWS App Mesh Virtual Nodes
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Migration & Breaking Changes
dns.service_name to dns.hostname and replace the backends attribute with backend configuration blocks using virtual_service_name. Existing resource state migrates automatically.Configuration & Setup
meshName, meshOwner, and name properties are immutable after creation. Plan these values carefully during initial setup.backend configuration blocks within the spec, setting virtualService.virtualServiceName to point to your backend service (e.g., “servicea.simpleapp.local”).Service Discovery & Monitoring
serviceDiscovery.dns.hostname or AWS Cloud Map with serviceDiscovery.awsCloudMap (specifying serviceName, namespaceName, and optional attributes).healthCheck within the listener, specifying protocol, path, healthyThreshold, unhealthyThreshold, timeoutMillis, and intervalMillis.logging.accessLog.file.path to the spec, typically set to “/dev/stdout” to send logs to standard output.Using a different cloud?
Explore networking guides for other cloud providers: