Skip to main content

Dart App on CloudFlow

Learn how to run a "Hello World" Dart app at the edge for low latency and high availability. You can use our repo as a template, or perform the steps yourself using the Kubernetes dashboard or kubectl commands.

Step by Step

Following are step-by-step instructions to deploy a Dart "Hello World" application to the edge on CloudFlow. We'll Dockerize it, and deploy it on CloudFlow.

Prerequisites

  • You need Docker installed so that you can build a docker image.

Create the Dart App

Create a new directory for your app.

mkdir my-dart-app
cd my-dart-app

Create directory bin with a new file server.dart with the following code.

server.dart
import 'dart:convert';
import 'dart:io';

import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as shelf_io;
import 'package:shelf_router/shelf_router.dart' as shelf_router;
import 'package:shelf_static/shelf_static.dart' as shelf_static;

Future<void> main() async {
// If the "PORT" environment variable is set, listen to it. Otherwise, 8080.
// https://cloud.google.com/run/docs/reference/container-contract#port
final port = int.parse(Platform.environment['PORT'] ?? '8080');

// See https://pub.dev/documentation/shelf/latest/shelf/Cascade-class.html
final cascade = Cascade()
// First, serve files from the 'public' directory
.add(_staticHandler)
// If a corresponding file is not found, send requests to a `Router`
.add(_router);

// See https://pub.dev/documentation/shelf/latest/shelf_io/serve.html
final server = await shelf_io.serve(
// See https://pub.dev/documentation/shelf/latest/shelf/logRequests.html
logRequests()
// See https://pub.dev/documentation/shelf/latest/shelf/MiddlewareExtensions/addHandler.html
.addHandler(cascade.handler),
InternetAddress.anyIPv4, // Allows external connections
port,
);

print('Serving at http://${server.address.host}:${server.port}');
}

// Serve files from the file system.
final _staticHandler =
shelf_static.createStaticHandler('public', defaultDocument: 'index.html');

// Router instance to handler requests.
final _router = shelf_router.Router()
..get('/helloworld', _helloWorldHandler);

Response _helloWorldHandler(Request request) => Response.ok('Hello World!');

Create a directory called public in the root directory, and create a new file inside the public directory called index.html with the following content.

index.html
<html5>
<head>
<title>Dart Example on CloudFlow</title>
</head>
<body>
<h1>Hello World from Dart on CloudFlow!</h1>
</body>
</html5>

Dockerize It

Let's build the container image that we'll deploy to CloudFlow. First make a Dockerfile in your root directory with the following content.

Dockerfile
# Official Dart image: https://hub.docker.com/_/dart
# Specify the Dart SDK base image version using dart:<version> (ex: dart:2.12)
FROM dart:stable AS build

# Resolve app dependencies.
WORKDIR /app
COPY pubspec.* ./
RUN dart pub get

# Copy app source code and AOT compile it.
COPY . .
# Ensure packages are still up-to-date if anything has changed
RUN dart pub get --offline
RUN dart compile exe bin/server.dart -o bin/server

# Build minimal serving image from AOT-compiled `/server` and required system
# libraries and configuration files stored in `/runtime/` from the build stage.
FROM scratch
COPY --from=build /runtime/ /
COPY --from=build /app/bin/server /app/bin/

# Include files in the /public directory to enable static asset handling
COPY --from=build /app/public/ /public

# Start server.
EXPOSE 8080
CMD ["/app/bin/server"]

Now create a file called pubspec.yaml in the root directory, this is where we will define our dependencies.

pubspec.yaml
name: helloworld
publish_to: none

environment:
sdk: ">=2.12.0 <3.0.0"

dependencies:
shelf: ^1.2.0
shelf_router: ^1.0.0
shelf_static: ^1.0.0

dev_dependencies:
http: ^0.13.0
lints: ^2.0.0
test: ^1.15.0
test_process: ^2.0.0

Finally, create a file called .dockerignore in the root directory, this is where we will define files that we don't want to include in our container image.

.dockerignore
.dockerignore
Dockerfile
build/
.dart_tool/
.git/
.github/
.gitignore
.packages

Build and tag it.

docker build . -t ghcr.io/YOUR_GITHUB_USERNAME/my-dart-app:prod

Launch it locally to test it.

docker run -p 8080:8080 ghcr.io/YOUR_GITHUB_USERNAME/my-dart-app:prod
curl http://localhost:8080

Push It

Push it to GitHub Packages. This makes it available to CloudFlow.

docker push ghcr.io/YOUR_GITHUB_USERNAME/my-dart-app:prod

Be sure to make it public. To see your packages and make this change, visit https://github.com/YOUR_GITHUB_USERNAME?tab=packages

Deploy It

Next, use the Create Project command in the CloudFlow Console in order to deploy your new container. Use the image name ghcr.io/YOUR_GITHUB_USERNAME/my-dart-app:prod with port 8080.

See the pods running on CloudFlow's network with either the Kubernetes dashboard or kubectl get pods -o wide. The -o wide switch shows where your app is running according to the default AEE location optimization strategy. Your app will be optimally deployed according to traffic. In lieu of significant traffic, your deployment will be made to default locations.

Try kubectl logs POD to see the log message reporting that the server is listening on port 8080 (Serving at http://0.0.0.0:8080)

Finally, follow the instructions that configure DNS and TLS.

See What You've Built

See the "Hello World!" app you've built by visiting the https://YOUR.DOMAIN.COM, substituting YOUR.DOMAIN.COM according to your DNS and HTTPS configuration.