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