Merge pull request #481 from outline/docker-development
Docker Development
This commit is contained in:
14
.env.sample
14
.env.sample
@@ -2,11 +2,11 @@
|
||||
#
|
||||
# Please use `openssl rand -hex 32` to create SECRET_KEY
|
||||
|
||||
DATABASE_URL=postgres://user:pass@example.com:5432/outline
|
||||
DATABASE_URL_TEST=postgres://user:pass@example.com:5432/outline-test
|
||||
DATABASE_URL=postgres://user:pass@localhost:5432/outline
|
||||
DATABASE_URL_TEST=postgres://user:pass@localhost:5432/outline-test
|
||||
SECRET_KEY=F0E5AD933D7F6FD8F4DBB3E038C501C052DC0593C686D21ACB30AE205D2F634B
|
||||
PORT=3000
|
||||
REDIS_URL=redis://localhost:6379
|
||||
REDIS_URL=redis://redis:6379
|
||||
SLACK_KEY=71315967491.XXXXXXXXXX
|
||||
SLACK_SECRET=d2dc414f9953226bad0a356c794XXXXX
|
||||
URL=http://localhost:3000
|
||||
@@ -14,9 +14,15 @@ DEPLOYMENT=hosted
|
||||
ENABLE_UPDATES=true
|
||||
GOOGLE_ANALYTICS_ID=
|
||||
|
||||
AWS_ACCESS_KEY_ID=notcheckedindev
|
||||
AWS_SECRET_ACCESS_KEY=notcheckedindev
|
||||
AWS_S3_UPLOAD_BUCKET_URL=http://s3:4569
|
||||
AWS_S3_UPLOAD_BUCKET_NAME=outline-dev
|
||||
AWS_S3_UPLOAD_MAX_SIZE=26214400
|
||||
|
||||
SMTP_HOST=
|
||||
SMTP_PORT=
|
||||
SMTP_USERNAME=
|
||||
SMTP_PASSWORD=
|
||||
SMTP_FROM_EMAIL=
|
||||
SMTP_REPLY_EMAIL=
|
||||
SMTP_REPLY_EMAIL=
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,3 +3,4 @@ node_modules/*
|
||||
.env
|
||||
npm-debug.log
|
||||
.DS_Store
|
||||
fakes3/*
|
||||
|
||||
10
Dockerfile
Normal file
10
Dockerfile
Normal file
@@ -0,0 +1,10 @@
|
||||
FROM node:latest
|
||||
|
||||
ENV APP_PATH /opt/outline
|
||||
RUN mkdir -p $APP_PATH
|
||||
|
||||
WORKDIR $APP_PATH
|
||||
COPY . $APP_PATH
|
||||
RUN yarn
|
||||
RUN cp -r /opt/outline/node_modules /opt/node_modules
|
||||
|
||||
13
Makefile
Normal file
13
Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
up:
|
||||
docker-compose up -d redis postgres s3
|
||||
docker-compose run --rm outline yarn sequelize db:migrate
|
||||
docker-compose up outline
|
||||
|
||||
build:
|
||||
docker-compose build --pull outline
|
||||
|
||||
destroy:
|
||||
docker-compose stop
|
||||
docker-compose rm -f
|
||||
|
||||
.PHONY: up build destroy # let's go to reserve rules names
|
||||
28
README.md
28
README.md
@@ -8,37 +8,27 @@ An open, extensible, knowledge base for your team built using React and Node.js.
|
||||
|
||||
## Installation
|
||||
|
||||
Outline requires following dependencies to work:
|
||||
Outline requires the following dependencies:
|
||||
|
||||
- Postgres >=9.5
|
||||
- Redis
|
||||
- S3 bucket configured to support CORS uploads
|
||||
- Slack developer application
|
||||
|
||||
To install and run the application:
|
||||
In development you can quickly can an environment running using Docker by
|
||||
following these steps:
|
||||
|
||||
1. Install dependencies with `yarn`
|
||||
1. Register a Slack app at https://api.slack.com/apps
|
||||
1. Copy the file `.env.sample` to `.env` and fill out the keys
|
||||
1. Run DB migrations `yarn sequelize db:migrate`
|
||||
|
||||
To run Outline in development mode with server and frontend code reloading:
|
||||
1. Install [Docker for Desktop](https://www.docker.com) if you don't already have it.
|
||||
1. Register a Slack app at https://api.slack.com/apps
|
||||
1. Copy the file `.env.sample` to `.env` and fill out the Slack keys, everything
|
||||
else should work well for development.
|
||||
1. Run `make up`. This will download dependencies, build and launch a development version of Outline.
|
||||
|
||||
```shell
|
||||
yarn dev
|
||||
```
|
||||
|
||||
To run Outline in production mode:
|
||||
|
||||
```shell
|
||||
yarn start
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Server
|
||||
|
||||
To enable debugging statements, set the following env vars:
|
||||
To enable debugging statements, add the following to your `.env` file:
|
||||
|
||||
```
|
||||
DEBUG=sql,cache,presenters
|
||||
|
||||
39
docker-compose.yml
Normal file
39
docker-compose.yml
Normal file
@@ -0,0 +1,39 @@
|
||||
version: "3"
|
||||
services:
|
||||
redis:
|
||||
image: redis
|
||||
ports:
|
||||
- "6379:6379"
|
||||
postgres:
|
||||
image: postgres
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
POSTGRES_USER: user
|
||||
POSTGRES_PASSWORD: pass
|
||||
POSTGRES_DB: outline
|
||||
s3:
|
||||
image: lphoward/fake-s3
|
||||
ports:
|
||||
- "4569:4569"
|
||||
volumes:
|
||||
- ./fakes3:/fakes3_root
|
||||
outline:
|
||||
image: outline:v001
|
||||
command: yarn dev
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
pull: 1
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- .:/opt/outline
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
- s3
|
||||
environment:
|
||||
NODE_PATH: "/opt/outline/node_modules:/opt/node_modules"
|
||||
PATH: "/opt/outline/node_modules/.bin:/opt/node_modules/.bin:$PATH"
|
||||
@@ -1,8 +1,7 @@
|
||||
// @flow
|
||||
import uuid from 'uuid';
|
||||
import Router from 'koa-router';
|
||||
|
||||
import { makePolicy, signPolicy } from '../utils/s3';
|
||||
import { makePolicy, signPolicy, publicS3Endpoint } from '../utils/s3';
|
||||
import auth from './middlewares/authentication';
|
||||
import { presentUser } from '../presenters';
|
||||
|
||||
@@ -21,11 +20,12 @@ router.post('user.s3Upload', auth(), async ctx => {
|
||||
const s3Key = uuid.v4();
|
||||
const key = `uploads/${ctx.state.user.id}/${s3Key}/${filename}`;
|
||||
const policy = makePolicy();
|
||||
const endpoint = publicS3Endpoint();
|
||||
|
||||
ctx.body = {
|
||||
data: {
|
||||
maxUploadSize: process.env.AWS_S3_UPLOAD_MAX_SIZE,
|
||||
uploadUrl: process.env.AWS_S3_UPLOAD_BUCKET_URL,
|
||||
uploadUrl: endpoint,
|
||||
form: {
|
||||
AWSAccessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
||||
'Cache-Control': 'max-age=31557600',
|
||||
@@ -37,7 +37,7 @@ router.post('user.s3Upload', auth(), async ctx => {
|
||||
},
|
||||
asset: {
|
||||
contentType: kind,
|
||||
url: `${process.env.AWS_S3_UPLOAD_BUCKET_URL}${key}`,
|
||||
url: `${endpoint}/${key}`,
|
||||
name: filename,
|
||||
size,
|
||||
},
|
||||
|
||||
@@ -6,15 +6,10 @@ import invariant from 'invariant';
|
||||
import fetch from 'isomorphic-fetch';
|
||||
import bugsnag from 'bugsnag';
|
||||
|
||||
AWS.config.update({
|
||||
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
||||
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
||||
});
|
||||
|
||||
const AWS_SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY;
|
||||
const AWS_S3_UPLOAD_BUCKET_NAME = process.env.AWS_S3_UPLOAD_BUCKET_NAME;
|
||||
|
||||
const makePolicy = () => {
|
||||
export const makePolicy = () => {
|
||||
const policy = {
|
||||
conditions: [
|
||||
{ bucket: process.env.AWS_S3_UPLOAD_BUCKET_NAME },
|
||||
@@ -32,7 +27,7 @@ const makePolicy = () => {
|
||||
return new Buffer(JSON.stringify(policy)).toString('base64');
|
||||
};
|
||||
|
||||
const signPolicy = (policy: any) => {
|
||||
export const signPolicy = (policy: any) => {
|
||||
invariant(AWS_SECRET_ACCESS_KEY, 'AWS_SECRET_ACCESS_KEY not set');
|
||||
const signature = crypto
|
||||
.createHmac('sha1', AWS_SECRET_ACCESS_KEY)
|
||||
@@ -42,16 +37,33 @@ const signPolicy = (policy: any) => {
|
||||
return signature;
|
||||
};
|
||||
|
||||
const uploadToS3FromUrl = async (url: string, key: string) => {
|
||||
const s3 = new AWS.S3();
|
||||
export const publicS3Endpoint = () => {
|
||||
// lose trailing slash if there is one and convert fake-s3 url to localhost
|
||||
// for access outside of docker containers in local development
|
||||
const host = process.env.AWS_S3_UPLOAD_BUCKET_URL.replace(
|
||||
's3:',
|
||||
'localhost:'
|
||||
).replace(/\/$/, '');
|
||||
|
||||
return `${host}/${process.env.AWS_S3_UPLOAD_BUCKET_NAME}`;
|
||||
};
|
||||
|
||||
export const uploadToS3FromUrl = async (url: string, key: string) => {
|
||||
const s3 = new AWS.S3({
|
||||
s3ForcePathStyle: true,
|
||||
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
||||
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
||||
endpoint: new AWS.Endpoint(process.env.AWS_S3_UPLOAD_BUCKET_URL),
|
||||
});
|
||||
invariant(AWS_S3_UPLOAD_BUCKET_NAME, 'AWS_S3_UPLOAD_BUCKET_NAME not set');
|
||||
|
||||
try {
|
||||
// $FlowIssue dunno it's fine
|
||||
// $FlowIssue https://github.com/facebook/flow/issues/2171
|
||||
const res = await fetch(url);
|
||||
const buffer = await res.buffer();
|
||||
await s3
|
||||
.putObject({
|
||||
ACL: 'public-read',
|
||||
Bucket: process.env.AWS_S3_UPLOAD_BUCKET_NAME,
|
||||
Key: key,
|
||||
ContentType: res.headers['content-type'],
|
||||
@@ -59,10 +71,14 @@ const uploadToS3FromUrl = async (url: string, key: string) => {
|
||||
Body: buffer,
|
||||
})
|
||||
.promise();
|
||||
return `https://s3.amazonaws.com/${AWS_S3_UPLOAD_BUCKET_NAME}/${key}`;
|
||||
} catch (e) {
|
||||
bugsnag.notify(e);
|
||||
|
||||
const endpoint = publicS3Endpoint();
|
||||
return `${endpoint}/${key}`;
|
||||
} catch (err) {
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
bugsnag.notify(err);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export { makePolicy, signPolicy, uploadToS3FromUrl };
|
||||
|
||||
Reference in New Issue
Block a user