mirror of https://github.com/dapr/quickstarts.git
Docker Compose Sample (#211)
* add docker-compose sample * add Makefile * add README * small tweaks to README * Update README.md * updated based on feedback * small updates and reword * Add --components-path to work with 0.8.0 changes * Change port of redis to 6380 as 6379 would mostly likely be already in use because of the redis container that dapr spins up during "dapr init" * Add --components-path to the list of options * Change host port instead of container port in README * Change host port instead of container port Co-authored-by: Mark Fussell <mfussell@microsoft.com> Co-authored-by: Young Bu Park <youngp@microsoft.com> Co-authored-by: Pruthvidhar R Dhodda <60198385+pruthvidhodda@users.noreply.github.com>
This commit is contained in:
parent
ae4c4e6281
commit
0ff4414177
|
@ -0,0 +1,2 @@
|
||||||
|
.dockerfiles
|
||||||
|
*.override.*
|
|
@ -0,0 +1,133 @@
|
||||||
|
# Dapr with Docker-Compose
|
||||||
|
|
||||||
|
This sample demonstrates how to get Dapr running locally with Docker Compose. This uses the same applications as the `1.hello-world` sample, please review those docs for further information on the applicaiton architecture.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
Clone this repo using `git clone https://github.com/dapr/samples.git` and go to the directory named */10.hello-docker-compose*
|
||||||
|
|
||||||
|
- [Docker](https://docs.docker.com/)
|
||||||
|
- [Docker Compose](https://docs.docker.com/compose/install/)
|
||||||
|
|
||||||
|
## Reviewing the Docker Compose Definition
|
||||||
|
|
||||||
|
Review the Docker Compose file *./docker-compose.yml* below:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
############################
|
||||||
|
# Node app + Dapr sidecar
|
||||||
|
############################
|
||||||
|
nodeapp:
|
||||||
|
build: ./node
|
||||||
|
ports:
|
||||||
|
- "50002:50002"
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
- placement
|
||||||
|
networks:
|
||||||
|
- hello-dapr
|
||||||
|
nodeapp-dapr:
|
||||||
|
image: "daprio/daprd:edge"
|
||||||
|
command: ["./daprd",
|
||||||
|
"-app-id", "nodeapp",
|
||||||
|
"-app-port", "3000",
|
||||||
|
"-placement-address", "placement:50006",
|
||||||
|
"-dapr-grpc-port", "50002",
|
||||||
|
"-components-path", "/components"]
|
||||||
|
volumes:
|
||||||
|
- "./components/:/components"
|
||||||
|
depends_on:
|
||||||
|
- nodeapp
|
||||||
|
network_mode: "service:nodeapp"
|
||||||
|
############################
|
||||||
|
# Python app + Dapr sidecar
|
||||||
|
############################
|
||||||
|
pythonapp:
|
||||||
|
build: ./python
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
- placement
|
||||||
|
networks:
|
||||||
|
- hello-dapr
|
||||||
|
pythonapp-dapr:
|
||||||
|
image: "daprio/daprd:edge"
|
||||||
|
command: ["./daprd",
|
||||||
|
"-app-id", "pythonapp",
|
||||||
|
"-placement-address", "placement:50006",
|
||||||
|
"-components-path", "/components"]
|
||||||
|
volumes:
|
||||||
|
- "./components/:/components"
|
||||||
|
depends_on:
|
||||||
|
- pythonapp
|
||||||
|
network_mode: "service:pythonapp"
|
||||||
|
############################
|
||||||
|
# Dapr placement service
|
||||||
|
############################
|
||||||
|
placement:
|
||||||
|
image: "daprio/dapr"
|
||||||
|
command: ["./placement", "-port", "50006"]
|
||||||
|
ports:
|
||||||
|
- "50006:50006"
|
||||||
|
networks:
|
||||||
|
- hello-dapr
|
||||||
|
############################
|
||||||
|
# Redis state store
|
||||||
|
############################
|
||||||
|
redis:
|
||||||
|
image: "redis:alpine"
|
||||||
|
ports:
|
||||||
|
- "6380:6379"
|
||||||
|
networks:
|
||||||
|
- hello-dapr
|
||||||
|
networks:
|
||||||
|
hello-dapr:
|
||||||
|
```
|
||||||
|
|
||||||
|
### Services
|
||||||
|
This Docker Compose defintion has the following containerized services:
|
||||||
|
- `nodeapp` // The node app
|
||||||
|
- `nodeapp-dapr` // The node app Dapr sidecar
|
||||||
|
- `pythonapp` // The python app
|
||||||
|
- `pythonapp-dapr` // The python app Dapr sidecar
|
||||||
|
- `placement` // Dapr's placement service
|
||||||
|
- `redis` // Redis
|
||||||
|
|
||||||
|
### Networking
|
||||||
|
Each of these services is deployed to the `hello-dapr` Docker network and have their own IP on that network.
|
||||||
|
The `nodeapp-dapr` and `pythonapp-dapr` services are sharing a network namespace with their associated app service by using [`network_mode`](https://docs.docker.com/compose/compose-file/#network_mode).
|
||||||
|
This means that the app and the sidecars are able to communicate over their localhost interface.
|
||||||
|
|
||||||
|
> Ports are still bound on the host machine, therefore, we need to ensure we avoid port conflicts.
|
||||||
|
|
||||||
|
### Volumes
|
||||||
|
In order to get Dapr to load the redis statestore and pubsub components, you need to mount the
|
||||||
|
`./components` directory to the default working directory. These component definitions have been modified
|
||||||
|
to talk to redis using a DNS name `redis` rather than localhost. This resolves on the Docker network to
|
||||||
|
the IP of the container running redis.
|
||||||
|
|
||||||
|
## Deploy the Docker Compose Definition
|
||||||
|
To deploy the above `docker-compose.yml` you can run:
|
||||||
|
```
|
||||||
|
make run
|
||||||
|
```
|
||||||
|
> If you want to change the Dapr Docker image used in the deployment, you can
|
||||||
|
set the env var `DAPR_IMAGE` and run `make run`. This generates
|
||||||
|
a `docker-compose.override.yml` file using your custom image. If you want
|
||||||
|
to revert to the default Dapr Docker image, you'll need to remove this file.
|
||||||
|
|
||||||
|
altentiavely, you can just use Docker Compose directly:
|
||||||
|
```
|
||||||
|
docker-compose up
|
||||||
|
```
|
||||||
|
|
||||||
|
## Clean up
|
||||||
|
|
||||||
|
To tear down the Docker Compose deployment, you can run:
|
||||||
|
```
|
||||||
|
docker-compose down
|
||||||
|
```
|
||||||
|
|
||||||
|
## Additional Resources:
|
||||||
|
|
||||||
|
[Overview of Docker Compose](https://docs.docker.com/compose/)
|
|
@ -0,0 +1,11 @@
|
||||||
|
apiVersion: dapr.io/v1alpha1
|
||||||
|
kind: Component
|
||||||
|
metadata:
|
||||||
|
name: pubsub
|
||||||
|
spec:
|
||||||
|
type: pubsub.redis
|
||||||
|
metadata:
|
||||||
|
- name: redisHost
|
||||||
|
value: redis:6379
|
||||||
|
- name: redisPassword
|
||||||
|
value: ""
|
|
@ -0,0 +1,11 @@
|
||||||
|
apiVersion: dapr.io/v1alpha1
|
||||||
|
kind: Component
|
||||||
|
metadata:
|
||||||
|
name: statestore
|
||||||
|
spec:
|
||||||
|
type: state.redis
|
||||||
|
metadata:
|
||||||
|
- name: redisHost
|
||||||
|
value: redis:6379
|
||||||
|
- name: redisPassword
|
||||||
|
value: ""
|
|
@ -0,0 +1,69 @@
|
||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
############################
|
||||||
|
# Node app + Dapr sidecar
|
||||||
|
############################
|
||||||
|
nodeapp:
|
||||||
|
build: ./node
|
||||||
|
ports:
|
||||||
|
- "50002:50002"
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
- placement
|
||||||
|
networks:
|
||||||
|
- hello-dapr
|
||||||
|
nodeapp-dapr:
|
||||||
|
image: "daprio/daprd:edge"
|
||||||
|
command: ["./daprd",
|
||||||
|
"-app-id", "nodeapp",
|
||||||
|
"-app-port", "3000",
|
||||||
|
"-placement-address", "placement:50006",
|
||||||
|
"-dapr-grpc-port", "50002",
|
||||||
|
"-components-path", "/components"]
|
||||||
|
volumes:
|
||||||
|
- "./components/:/components"
|
||||||
|
depends_on:
|
||||||
|
- nodeapp
|
||||||
|
network_mode: "service:nodeapp"
|
||||||
|
############################
|
||||||
|
# Python app + Dapr sidecar
|
||||||
|
############################
|
||||||
|
pythonapp:
|
||||||
|
build: ./python
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
- placement
|
||||||
|
networks:
|
||||||
|
- hello-dapr
|
||||||
|
pythonapp-dapr:
|
||||||
|
image: "daprio/daprd:edge"
|
||||||
|
command: ["./daprd",
|
||||||
|
"-app-id", "pythonapp",
|
||||||
|
"-placement-address", "placement:50006",
|
||||||
|
"-components-path", "/components"]
|
||||||
|
volumes:
|
||||||
|
- "./components/:/components"
|
||||||
|
depends_on:
|
||||||
|
- pythonapp
|
||||||
|
network_mode: "service:pythonapp"
|
||||||
|
############################
|
||||||
|
# Dapr placement service
|
||||||
|
############################
|
||||||
|
placement:
|
||||||
|
image: "daprio/dapr"
|
||||||
|
command: ["./placement", "-port", "50006"]
|
||||||
|
ports:
|
||||||
|
- "50006:50006"
|
||||||
|
networks:
|
||||||
|
- hello-dapr
|
||||||
|
############################
|
||||||
|
# Redis state store
|
||||||
|
############################
|
||||||
|
redis:
|
||||||
|
image: "redis:alpine"
|
||||||
|
ports:
|
||||||
|
- "6380:6379"
|
||||||
|
networks:
|
||||||
|
- hello-dapr
|
||||||
|
networks:
|
||||||
|
hello-dapr:
|
|
@ -0,0 +1,17 @@
|
||||||
|
DOCKER_COMPOSE:=docker-compose
|
||||||
|
DOCKER_COMPOSE_FILE:=docker-compose.yml
|
||||||
|
DOCKER_COMPOSE_OVERRIDE_FILE:=docker-compose.override.yml
|
||||||
|
|
||||||
|
DAPR_IMAGE:=${DAPR_IMAGE}
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build:
|
||||||
|
$(DOCKER_COMPOSE) build
|
||||||
|
|
||||||
|
.PHONY: run
|
||||||
|
run:
|
||||||
|
ifneq ($(DAPR_IMAGE),)
|
||||||
|
cp $(DOCKER_COMPOSE_FILE) $(DOCKER_COMPOSE_OVERRIDE_FILE)
|
||||||
|
sed -i 's,daprio\/daprd:edge,$(DAPR_IMAGE),g' $(DOCKER_COMPOSE_OVERRIDE_FILE)
|
||||||
|
endif
|
||||||
|
$(DOCKER_COMPOSE) up
|
|
@ -0,0 +1,2 @@
|
||||||
|
node_modules
|
||||||
|
.dockerfiles
|
|
@ -0,0 +1,6 @@
|
||||||
|
FROM node:8-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
COPY . .
|
||||||
|
RUN npm install
|
||||||
|
EXPOSE 3000
|
||||||
|
CMD [ "node", "app.js" ]
|
|
@ -0,0 +1,63 @@
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
|
||||||
|
const express = require('express');
|
||||||
|
const bodyParser = require('body-parser');
|
||||||
|
require('isomorphic-fetch');
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
app.use(bodyParser.json());
|
||||||
|
|
||||||
|
const daprPort = process.env.DAPR_HTTP_PORT || 3500;
|
||||||
|
const stateStoreName = `statestore`;
|
||||||
|
const stateUrl = `http://localhost:${daprPort}/v1.0/state/${stateStoreName}`;
|
||||||
|
const port = 3000;
|
||||||
|
|
||||||
|
app.get('/order', (_req, res) => {
|
||||||
|
fetch(`${stateUrl}/order`)
|
||||||
|
.then((response) => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw "Could not get state.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.text();
|
||||||
|
}).then((orders) => {
|
||||||
|
res.send(orders);
|
||||||
|
}).catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
res.status(500).send({message: error});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('/neworder', (req, res) => {
|
||||||
|
const data = req.body.data;
|
||||||
|
const orderId = data.orderId;
|
||||||
|
console.log("Got a new order! Order ID: " + orderId);
|
||||||
|
|
||||||
|
const state = [{
|
||||||
|
key: "order",
|
||||||
|
value: data
|
||||||
|
}];
|
||||||
|
|
||||||
|
fetch(stateUrl, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(state),
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
}).then((response) => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw "Failed to persist state.";
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Successfully persisted state.");
|
||||||
|
res.status(200).send();
|
||||||
|
}).catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
res.status(500).send({message: error});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(port, () => console.log(`Node App listening on port ${port}!`));
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"name": "node_server",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "app.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"body-parser": "^1.18.3",
|
||||||
|
"express": "^4.16.4",
|
||||||
|
"isomorphic-fetch": "^2.2.1"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
.dockerfiles
|
|
@ -0,0 +1,6 @@
|
||||||
|
FROM python:3.7.1-alpine3.8
|
||||||
|
WORKDIR /app
|
||||||
|
COPY . .
|
||||||
|
RUN pip install requests
|
||||||
|
ENTRYPOINT ["python"]
|
||||||
|
CMD ["app.py"]
|
|
@ -0,0 +1,23 @@
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# Licensed under the MIT License.
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
|
import os
|
||||||
|
|
||||||
|
dapr_port = os.getenv("DAPR_HTTP_PORT", 3500)
|
||||||
|
dapr_url = "http://localhost:{}/v1.0/invoke/nodeapp/method/neworder".format(dapr_port)
|
||||||
|
|
||||||
|
n = 0
|
||||||
|
while True:
|
||||||
|
n += 1
|
||||||
|
message = {"data": {"orderId": n}}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.post(dapr_url, json=message)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
time.sleep(1)
|
Loading…
Reference in New Issue