From 3d82eb3eef89226b6cef383066ce05dc13b53e96 Mon Sep 17 00:00:00 2001 From: Piers Karsenbarg Date: Mon, 21 Jun 2021 14:49:28 +0100 Subject: [PATCH] Added docker multi-container example (#1022) * Added example for a multi-container application * Fixing linting errors --- docker-ts-multi-container-app/.gitignore | 2 + docker-ts-multi-container-app/Pulumi.yaml | 3 + docker-ts-multi-container-app/README.md | 114 ++++++++++++++++++ docker-ts-multi-container-app/app/Dockerfile | 10 ++ docker-ts-multi-container-app/app/index.js | 33 +++++ .../app/package.json | 15 +++ docker-ts-multi-container-app/index.ts | 59 +++++++++ docker-ts-multi-container-app/package.json | 10 ++ docker-ts-multi-container-app/tsconfig.json | 18 +++ 9 files changed, 264 insertions(+) create mode 100644 docker-ts-multi-container-app/.gitignore create mode 100644 docker-ts-multi-container-app/Pulumi.yaml create mode 100644 docker-ts-multi-container-app/README.md create mode 100644 docker-ts-multi-container-app/app/Dockerfile create mode 100644 docker-ts-multi-container-app/app/index.js create mode 100644 docker-ts-multi-container-app/app/package.json create mode 100644 docker-ts-multi-container-app/index.ts create mode 100644 docker-ts-multi-container-app/package.json create mode 100644 docker-ts-multi-container-app/tsconfig.json diff --git a/docker-ts-multi-container-app/.gitignore b/docker-ts-multi-container-app/.gitignore new file mode 100644 index 000000000..c6958891d --- /dev/null +++ b/docker-ts-multi-container-app/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/node_modules/ diff --git a/docker-ts-multi-container-app/Pulumi.yaml b/docker-ts-multi-container-app/Pulumi.yaml new file mode 100644 index 000000000..d6b5b6c1f --- /dev/null +++ b/docker-ts-multi-container-app/Pulumi.yaml @@ -0,0 +1,3 @@ +name: docker-ts-multi-container-app +runtime: nodejs +description: Example app using multiple docker containers diff --git a/docker-ts-multi-container-app/README.md b/docker-ts-multi-container-app/README.md new file mode 100644 index 000000000..bfbc64f98 --- /dev/null +++ b/docker-ts-multi-container-app/README.md @@ -0,0 +1,114 @@ +[![Deploy](https://get.pulumi.com/new/button.svg)](https://app.pulumi.com/new) + +# Docker multi-container example + +This example Pulumi application runs two containers locally, one Redis container and one built from the application in the `app` folder. The application queries the Redis database and returns the number of times the page has been viewed. + +## Prerequisites + +To run this example, make sure [Docker](https://docs.docker.com/engine/installation/) is installed and running. + +## Running the App + +1. Create a new stack: + + ``` + $ pulumi stack init containers-dev + ``` + +1. Restore NPM modules via `npm install` or `yarn install`. + +1. Preview and deploy the app via `pulumi up`. The preview will take a few minutes, as it builds a Docker container. A total of 19 resources are created. + + ``` + $ pulumi up + ``` + + ``` + Updating (dev) + + View Live: https://app.pulumi.com/acmecorp/docker-ts-multi-container-app/dev/updates/1 + + Type Name Status + + pulumi:pulumi:Stack docker-ts-multi-container-app-dev created + + ├─ docker:image:Image appImage create + + ├─ docker:index:Network network create + + ├─ docker:index:RemoteImage redisImage create + + ├─ docker:index:Container redisContainer create + + └─ docker:index:Container appContainer create + + Diagnostics: + docker:image:Image (appImage): + warning: #1 [internal] load build definition from Dockerfile + #1 sha256:0d4d685ddff69a0240b26fdc352c1ce914133b71c905d1fa977c90c87fd2146a + #1 transferring dockerfile: 36B done + #1 DONE 0.4s + + #2 [internal] load .dockerignore + #2 sha256:24180ce9fb5e863c8cdccc1dd5cecca0118d138fd1a387c2ba99c0bd73eb0b46 + #2 transferring context: 2B done + #2 DONE 0.5s + + #3 [internal] load metadata for docker.io/library/node:16-alpine + #3 sha256:93febbdbcf5a756e6e084d46d56976a0630ae35cc38d744d3fb69ab9a7ce9b20 + #3 DONE 0.7s + + #4 [1/5] FROM docker.io/library/node:16-alpine@sha256:6b56197d33a56cd45d1d1214292b8851fa1b91b2ccc678cee7e5fd4260bd8fae + #4 sha256:155f61a07d0d5bd3922125fe0a1f61b6ad7c80fd53ad17af2014022698792303 + #4 DONE 0.0s + + #6 [internal] load build context + #6 sha256:de51bb2a6c39944feaa85aac4b0ef727d42885f4ce1547e0d76a290b76cdb7ec + #6 transferring context: 62B done + #6 DONE 0.2s + + #5 [2/5] WORKDIR /app + #5 sha256:36e7704b507e21cfc90eb97c19f220899eebe00ef73ab450f2f9b689e02e3154 + #5 CACHED + + #7 [3/5] COPY package.json . + #7 sha256:54933f5857daeae271dc204a253bbf96c17b66dac0dc2a94dfc082a68964cb6d + #7 CACHED + + #8 [4/5] RUN npm i + #8 sha256:75557c22149d35804b54234ece9155528520503babaad06969c30e8d0b5af67d + #8 CACHED + + #9 [5/5] COPY index.js . + #9 sha256:704a81bac2b5e5318ca3a0ca730516ff27bec81defa1333e99b1d5b31cf8835d + #9 CACHED + + #10 exporting to image + #10 sha256:e8c613e07b0b7ff33893b694f7759a10d42e180f2b4dc349fb57dc6b71dcab00 + #10 exporting layers done + #10 writing image sha256:9ec8e52bb05a93f69a72db72407265586836d85a612578c39c6883b291c18ce3 + #10 writing image sha256:9ec8e52bb05a93f69a72db72407265586836d85a612578c39c6883b291c18ce3 0.1s done + #10 naming to docker.io/library/app done + #10 DONE 0.3s + + Outputs: + url: "http://localhost:3000" + + Resources: + + 6 created + + Duration: 19s + ``` + +1. View the endpoint URL, and run curl: + + ```bash + $ pulumi stack output + Current stack outputs (1) + OUTPUT VALUE + url http://localhost:3000 + + $ curl $(pulumi stack output url) + I have been viewed 1 times + ``` + +1. Repeat the previous command multiple times to see the number of views increase. + +## Clean up + +To clean up resources, run `pulumi destroy` and answer the confirmation question at the prompt. \ No newline at end of file diff --git a/docker-ts-multi-container-app/app/Dockerfile b/docker-ts-multi-container-app/app/Dockerfile new file mode 100644 index 000000000..c807dbbbb --- /dev/null +++ b/docker-ts-multi-container-app/app/Dockerfile @@ -0,0 +1,10 @@ +FROM node:16-alpine +WORKDIR /app + +COPY package.json . +RUN npm i +COPY index.js . + +EXPOSE 3000 + +CMD [ "npm", "start" ] \ No newline at end of file diff --git a/docker-ts-multi-container-app/app/index.js b/docker-ts-multi-container-app/app/index.js new file mode 100644 index 000000000..706764a5e --- /dev/null +++ b/docker-ts-multi-container-app/app/index.js @@ -0,0 +1,33 @@ +const express = require("express"); +const redis = require("redis"); + +const app = express(); +const redisPort = process.env.REDIS_PORT +const redisHost = process.env.REDIS_HOST; +const redisClient = redis.createClient(redisPort, redisHost); +const redisKey = "numHits"; + +app.get("/", (req, res) => { + redisClient.get(redisKey, async (err, redisData) => { + if(err) throw err; + + if(redisData) { + console.log(redisData); + let jsonData = JSON.parse(redisData); + let currentVisits = jsonData.num; + let data = {num: currentVisits + 1}; + redisClient.set(redisKey, JSON.stringify(data)); + res.send(`I have been viewed ${currentVisits} times.`); + } else { + let data = {num: 1}; + redisClient.set(redisKey, JSON.stringify(data)); + res.send(`I have been viewed ${data.num} time.`) + } + }) +}); + +app.listen(3000, () => { + console.log("Node server started"); + console.log(`Redis Host: ${redisHost}`); + console.log(`Redis Port: ${redisPort}`); +}); \ No newline at end of file diff --git a/docker-ts-multi-container-app/app/package.json b/docker-ts-multi-container-app/app/package.json new file mode 100644 index 000000000..bfa2bf52f --- /dev/null +++ b/docker-ts-multi-container-app/app/package.json @@ -0,0 +1,15 @@ +{ + "name": "app", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "node ." + }, + "author": "", + "license": "ISC", + "dependencies": { + "express": "^4.17.1", + "redis": "^3.1.2" + } +} diff --git a/docker-ts-multi-container-app/index.ts b/docker-ts-multi-container-app/index.ts new file mode 100644 index 000000000..e897537f6 --- /dev/null +++ b/docker-ts-multi-container-app/index.ts @@ -0,0 +1,59 @@ +// Copyright 2016-2021, Pulumi Corporation. All rights reserved. + +import * as docker from "@pulumi/docker"; +import * as pulumi from "@pulumi/pulumi"; + +// Set defaults for redis +const redisPort = 6379; +const redisHost = "redisdb"; + +// Create docker network +const network = new docker.Network("network", { + name: "services", +}); + +// Get redis image +const redisImage = new docker.RemoteImage("redisImage", { + name: "redis:6.2", + keepLocally: true, +}); + +// Run redis image +const redisContainer = new docker.Container("redisContainer", { + image: redisImage.latest, + ports: [ + { internal: redisPort, external: redisPort}, + ], + networksAdvanced: [ + {name: network.name, aliases: [redisHost]}, + ], +}); + +// Create image from local app +const appImage = new docker.Image("appImage", { + build: { + context: "./app", + }, + imageName: "app", + skipPush: true, +}); + +// Set external port for app url +const appPort = 3000; + +// Run container from local app image +const appContainer = new docker.Container("appContainer", { + image: appImage.baseImageName, + ports: [ + {internal: appPort, external: appPort}, + ], + envs: [ + pulumi.interpolate`REDIS_HOST=${redisHost}`, + pulumi.interpolate`REDIS_PORT=${redisPort}`, + ] , + networksAdvanced: [ + {name: network.name}, + ], +}, {dependsOn: [redisContainer]}); + +export const url = pulumi.interpolate`http://localhost:${appPort}`; diff --git a/docker-ts-multi-container-app/package.json b/docker-ts-multi-container-app/package.json new file mode 100644 index 000000000..e515d649e --- /dev/null +++ b/docker-ts-multi-container-app/package.json @@ -0,0 +1,10 @@ +{ + "name": "docker-ts-multi-container-app", + "devDependencies": { + "@types/node": "^10.0.0" + }, + "dependencies": { + "@pulumi/docker": "^3.0.0", + "@pulumi/pulumi": "^3.0.0" + } +} diff --git a/docker-ts-multi-container-app/tsconfig.json b/docker-ts-multi-container-app/tsconfig.json new file mode 100644 index 000000000..ab65afa61 --- /dev/null +++ b/docker-ts-multi-container-app/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "strict": true, + "outDir": "bin", + "target": "es2016", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "experimentalDecorators": true, + "pretty": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.ts" + ] +}