Manage docker services for local development
- a local or remote docker host
- a docker client connected to that host
docker
anddocker-compose
located in your$PATH
node
v14.13 or higher, or v15 or higher
Add the module within your dev repo:
$ yarn add @uscreen.de/dev-service
To use one or multiple services for development, just add a list to your existing package.json, i.e.:
"services": [
"mongo:4",
"nginx:latest",
"redis"
]
Since this tool uses docker-compose for managing the services, we use the docker-specific image notation.
Next, run service install
and you will end up with a directory structure like:
.
├── node_modules
│ └── ...
├── package.json
│
├── services
│ ├── .compose
│ │ ├── mongo.yml
│ │ ├── nginx.yml
│ │ └── redis.yml
│ │
│ └── nginx/default.conf
│ ├── conf.d
│ │ └── default.conf
│ └── ssl
│ └── README
│
└── yarn.lock
Start all services with service start
. You can run service list
to see the stats of the started services, use service logs
for showing the services' logs (abort with ⌘-C).
By default, the started Nginx service returns Hello World
when called via curl localhost
.
Stop the services with service stop
.
Before service start
starts the services, it checks for two potential sources of error:
- Are other dev-service instances already running? If so, an appropriate warning message is displayed.
- Are ports already in use that are required by the services to be started? If so, an error message is displayed and the process is aborted.
This check can also be triggered separately via service check
$ service start
WARNING: dev-service is already running, started in following folder(s):
/path/to/some-other-dev-repo
In this example, another dev-service instance is already running, but there are no port conflicts. So the current service start
command is not cancelled.
$ service start
WARNING: dev-service is already running, started in following folder(s):
/path/to/some-other-dev-repo
ERROR: Required port(s) are already allocated:
- port 4222 is used by process with pid 52956 (/usr/local/opt/nats-server/bin/nats-server)
In this example, the port is used by a service started by an already running dev-service instance. To solve the issue, just run service stop
in the specified folder, i.e.:
$ cd /path/to/some-other-dev-repo
$ service stop
$ service start
ERROR: Required port(s) are already allocated:
- port 4222 is used by process with pid 52956 (/usr/local/opt/nats-server/bin/nats-server)
In this example, a running process (not started by dev-service) uses the port. This should be easily resolvable by killing that process, i.e.:
$ kill 52956
Please also check for supervised processes (pm2, launchd, etc.) in case of a process restarts after killing.
Install all services specified in package.json.
experimental feature
Creates a unique ID and uses it when naming the services' volumes, thus avoiding conflicts between volumes of different dev-service instances. Every subsequent call of service install
will (re-)create volume names with the same ID.
Warning: With this option, already installed services will no longer use already existing volumes not created with --enable-volumes-id
.
experimental feature
Maps services' volumes into local directories (./services/.volumes/<volume-name>
) instead of storing them inside of the Docker Desktop virtual machine. Every subsequent call of service install
will use this mappings.
Warning: With this option, already installed services will no longer use already existing volumes not created with --enable-mapped-volumes
.
Disables volumes ID and uses the project name when naming the services' volumes.
Warning: With this option, already installed services will no longer use already existing volumes created with --enable-volumes-id
or --enable-mapped-volumes
.
Start all or given installed service(s).
By default, this command checks the port availability before starting any service(s).
Stop all or given running service(s).
Restart all or given installed service(s).
Check port availability for all or given installed service(s).
List running services.
Show logs of all or given running services (abort with Ctrl-C).
Pulls current images for all or given installed service(s).
This action updates already existing images - within the boundaries of the respective service's tag. For updating an image beyond these boundaries, adjust the respective service's tag in your service definition and rerun service install
.
All provided services use their respective default ports:
service | used ports |
---|---|
redis | 6379 |
mongo | 27017 |
nats | 4222, 8222 |
nginx | 80, 443 |
rabbitmq | 5672, 15672 |
elasticsearch | 9200 |
The nginx service is configurable. You can modify the configuration(s) under ./services/nginx/conf.d/
, where you can also find the example default.conf
. Additionally, you can drop some ssl certificate files in ./services/nginx/ssl/
. The service will find them under /etc/nginx/ssl/
, so use this path in your configurations.
Your folder structure may look like this:
.
└── services
├── .compose
│ └── nginx.yml
│
└── nginx/default.conf
├── conf.d
│ ├── default.conf
│ └── someother.conf
└── ssl
├── your.domain.pem
└── your.domain.key
In default.conf
and/or someother.conf
:
...
ssl_certificate /etc/nginx/ssl/your.domain.pem;
ssl_certificate_key /etc/nginx/ssl/your.domain.key;
...
Besides the mentioned provided services, it's also possible to add customized services.
You can do this by adding an object with the appropriate docker-compose directives (compatible with compose file format 2.4) to the services
array in your package.json.
Say you want to add a specific version of elasticsearch with some customizing environment variables. Your package.json may look like this:
"services": [
{
"image": "docker.elastic.co/elasticsearch/elasticsearch:6.4.2",
"ports": ["9200:9200"],
"volumes": ["elasticsearch-data:/usr/share/elasticsearch/data:delegated"],
"environment": [
"cluster.name=dev-cluster",
"cluster.routing.allocation.disk.threshold_enabled=false",
"discovery.type=single-node",
"thread_pool.bulk.queue_size=200"
]
}
]
Running service install
will automatically create a partial docker-compose file from this directives in your services/.compose
folder:
version: "2.4"
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:6.4.2
container_name: "your-dev-repo_elasticsearch"
ports:
- 9200:9200
volumes:
- elasticsearch-data:/usr/share/elasticsearch/data:delegated
environment:
- cluster.name=dev-cluster
- cluster.routing.allocation.disk.threshold_enabled=false
- discovery.type=single-node
- thread_pool.bulk.queue_size=200
volumes:
elasticsearch-data:
external:
name: "foobar-dev-repo-elasticsearch-data"
This action has the following features & caveats:
- The service's name is automatically derived from the service's image name. Installing a service without specifying an image will fail.
- An adequate
container_name
is automatically added and will overwrite any existing container name - Volumes can only be given in "short syntax"
- All specified named volumes are automatically created if not already existing
- When referring to a file, keep in mind to specify the path relative to
services/.compose
If you want to map data from your host into a volume, it is best practice to put this data into a subfolder of the services
folder, named after the service it's mapped to. Also, you should use a relative path inside your service definition. A good example of this is the provided Nginx service. If we would define it inside of our package.json, it would look like this:
"services": [
{
"container_name": "your-dev-repo_nginx",
"image": "nginx:latest",
"ports": [
"80:80",
"443:443"
],
"volumes": [
"../nginx/conf.d:/etc/nginx/conf.d",
"../nginx/ssl:/etc/nginx/ssl"
]
}
]
And the folder structure would look like this:
.
└── services
├── .compose
│ ├── nginx.yml
│
└── nginx/default.conf
├── conf.d
│ └── default.conf
└── ssl
└── README
- fix tests to work in gitlab-ci
- fix tests to work in parallel
- add some examples
Format according to https://keepachangelog.com
- custom services with container ports lower than 60 now work as expected
- new
service pull
command
service install
options to customize volume naming/creation
service check
no more checks for ports given asCONTAINER
part of a port mapping (HOST:CONTAINER
)
- validation of custom service definitions
- vulnerabilites due to used packages
- bug with mismatching PIDs
- adjust node requirements
- display warning if other dev-service instances are running
- migrate to ESM (due to package requirements)
- don’t observe own ports in port check.
- support for node 10 (due to migration to ESM)
- avoiding errors when projectname contains certain special characters
- tests for
service check
service start
checks for used ports before starting any service(s)- updating list of provided services in readme
- fixing further false positives
service check
- package upgrades
- refactoring
service check
to avoid false positives
- avoiding side effects between different dev repos
- making tests work again after change in docker client api
- new service:
elasticsearch
- new service:
rabbitmq
- new
service check
to find processes blocking required ports
- optional service customization
- new
service restart
command
- expanding
service start
,service stop
andservice logs
by optional[service]
parameter
- package upgrades
- typo in readme
- new
service logs
command
- configure git ignore services/.compose folder
- initial version with basic commands
Licensed under MIT.
Published, Supported and Sponsored by u|screen