-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support Docker Compose-based development workflow #4
Conversation
services: | ||
database: | ||
image: mysql | ||
restart: on-failure |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's on-failure
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This tells Docker Compose to restart MySQL server when the server command exits with a non-zero exit code.
- MYSQL_ROOT_HOST=% | ||
|
||
api: | ||
restart: always |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's always
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
always
means that the container will restart whenever the entry point command (yarn dev
) exits, regardless of the exit code. yarn dev
is not supposed to exit at all so I'm not sure about using always
. on-failure
could also work.
source: . | ||
target: /code | ||
|
||
- type: volume |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the difference between type bind
and type volume
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bind
tells Docker to use an existing directory on the host OS as a volume inside the container. volume
, on the other hand, creates an empty volume, managed by Docker, so that the data can be persisted even if the container is stopped. We need bind
to mount the project code and allow automatic reloading on code changes. volume
is used to cache node_modules
separately from the host node_modules
so that dependencies do not conflict (suppose that the host is Windows, if the container overwrites node_modules
, some native dependencies will not work when running the server outside the container)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The volume created with type volume
can be inspected like this:
❯ docker volume inspect api_node_modules
[
{
"CreatedAt": "2017-10-30T07:23:24+02:00",
"Driver": "local",
"Labels": {
"com.docker.compose.project": "api",
"com.docker.compose.volume": "node_modules"
},
"Mountpoint": "/var/lib/docker/volumes/api_node_modules/_data",
"Name": "api_node_modules",
"Options": {},
"Scope": "local"
}
]
package.json
Outdated
@@ -13,7 +13,7 @@ | |||
"lint-ts": "tslint './*.ts' 'src/**/*.ts{,x}' -e 'src/typings/schema.ts' --project tsconfig.json", | |||
"generate-schema-types": "graphql-to-typescript schema.graphql src/typings/schema.ts", | |||
"generate-schema-types/dev": "nodemon --watch src/schema.graphql --exec 'run-p generate-schema-types'", | |||
"server/dev": "PORT=8080 nodemon --watch ./src --ext ts,graphql,tsx,json --exec 'ts-node src/server.ts --project ./src'", | |||
"server/dev": "PORT=8080 nodemon --watch ./src --ext ts,graphql,tsx,json --exec 'node --inspect -r 'ts-node/register' src/server.ts'", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
Cool stuff! So this containerizes our API dev workflow. Does it make sense to try to containerize the client-side dev workflow as well? |
With regard to the debugging issue that you're running into, I've encountered Docker networking issues in the past, and the thing I've had to do to resolve them is change the hostnames inside Docker from |
Yeah, I'm thinking we should containerize everything! It's awesome!
Interesting, I will give that a try. |
5693140
to
d94cce0
Compare
5a6ae58
to
6d704c1
Compare
I finally figured out why debugging didn't work. It turns out that the port inside the container is only exposed on localhost (it is not exposed to the network Docker Compose creates). This comment (nodejs/node#11591 (comment)) pointed me in the right direction. |
This PR introduces support for launching the API and database servers using Docker Compose.
This gives us all the benefits of Docker without compromising on development ergonomics:
We can lock all the system-wide dependencies (e.g. Node.js) to avoid version mismatch issues.
We also avoid conflicts with the host operating system. If we use Node.js 8 for our API, contributors do not need to use a Node.js version manager to change their system-wide Node.js installation to a version we use.
It's also more convenient to use Docker Compose to launch the API services instead of having to set up a MySQL server for development, which could also conflict with other development projects on the contributor's machine. One command is all that is needed to start the API and database servers:
This build and starts the servers in the background. We can simply go to localhost:8080/graphiql and query the API.
The running API server container will use the local project directory directly, i.e. it does not copy the files to the build image. This means that:
I've also set up the API image to use a Docker volume to cache the
node_modules
folder separately from the localnode_modules
directory so that native Node.js dependencies do not conflict with the host's equivalents. This volume is persisted even when the containers are stopped so it subsequent runs take a fraction of the time.This PR also changes the
yarn dev
command to use the standard Node.js executable instead ofts-node
. This allows us to use the--inspect
flag to debug TypeScript code using Visual Studio Code, including setting breakpoints and watch expressions.Unfortunately, this only works when the API server is not running in a container, even though the debugging port is exposed to the host operating system. I haven't figured out why yet.We could theoretically configure Docker Compose environment to be as close to the production environment as possible. For example, we can proxy the DNS requests of the development environment to route
api.hollowverse.com
to the containerized API development server. This PR does not do that, but using Docker Compose opens up the door for a lot of cool things!If, for any reason, we do not want to use Docker Compose, we can keep the current development workflow. This PR does not affect that in any way.
Tasks