Add support to auto-generate Dockerfile from domain config
subhashb opened this issue · 2 comments
Auto-generation of docker-compose.yml
This feature aims to automate the creation of docker-compose.yml from the project's configuration to simplify spinning up associated services for a Protean domain.
Docker will continue to be the tool of choice for ensuring consistency across environments, from development to production. However, crafting Docker Compose files manually:
- is a mundane task
- can be a time-consuming and error-prone task
Since developers specify their domain's core dependencies and environment within the Protean configuration file, the tool can automatically generate a docker-compose.yml
that seamlessly spins up services in the local development environment and can come in handy during deployment. Developers who need specific configurations for complex applications can tweak, enhance, and build on the generated docker-compose.yml
.
Background
Benefits of providing an easy path to docker-compose.yml
:
- Protean isolates domain models and allows full-blown business logic testing with stubs to test the entire domain without infra. However, the application must be tested with actual technologies before a change can be committed.
- Configuring all services in a ready-to-go
docker-compose.yml
will help developers test against different permutations and combinations without installing all the software locally. - A single Protean app can have multiple domains with separate docker files. Generating and maintaining a docker file per domain is a tedious task.
Detailed Proposal
Outline the feature in detail, including how it should work, any new concepts or terminology, configuration options, and examples of how it would be used.
- Decide what attributes hold aspects important from a
docker-compose.yml
perspective. - Extract relevant attributes: Use Protean's built-in config parsing. Load the domain. Extract relevant attributes.
- Populate a
docker-compose.yml
template withjinja2
, populated with relevant service sections. - Add a new CLI command to generate a Docker file at the root level:
protean generate docker-compose --domain-path=path/to/domain.py
- Throw an error if a
docker-compose.yml
already exists. - Output the file to the root of the app server in the same path as the domain file.
Alternatives Considered
NA.
Impact
NA.
Open Questions
- Should we go beyond the
docker-compose.yml
and support deployment artifacts for popular deployment patterns (Kubernetes, Fargate, etc.)? - Should we also aim to help generate a
Dockerfile
with a list of supported servers? (Gunicorn, flask, uwsgi, fastapi, etc.) - Will we need a separate configuration file to run apps from multiple domains?
- Should we add more attributes to the Protean config to hold docker-related options? Examples of options are Docker base image, additional_packages, environment_variables, etc. The alternative is to allow developers to add these to the Docker file directly. But then the Docker file will no longer be updated from Protean CLI.
Two additional steps I can think of:
- Add a Python CLI command to spin up services instead of
docker-compose up
. The script should shut down services on exit (when it receives SIGKILL or SIGTERM, for example) - Add a Python CLI command to test that all services are up defined in the Dockerfile are up and running, and accessible.
Objective1: Generate the dcoker-compose.yml
from the domain
The code traceback
-
The code first goes in
cli.py
a new command will introduced that will work on generation of thedocker-compose.yml
-
we can load the congif agrs by
domain.config
based on database and redis configs we will generate thedocker-compose.yml
here is the code snippet which will used to generatedocker-compose.yml
a way to generate the docker-compose.yml
we already have yaml in our package so it will not be a new installation
import yaml
def generate_docker_compose(service_name, image, ports=None, volumes=None):
docker_compose_content = {
'version': '3',
'services': {
service_name: {
'image': image
}
}
}
if ports:
docker_compose_content['services'][service_name]['ports'] = ports
if volumes:
docker_compose_content['services'][service_name]['volumes'] = volumes
return docker_compose_content
def save_to_file(content, filename='docker-compose.yml'):
with open(filename, 'w') as file:
yaml.dump(content, file, default_flow_style=False)
service_name = 'web'
image = 'nginx:latest'
ports = ['80:80']
volumes = ['./html:/usr/share/nginx/html']
docker_compose_content = generate_docker_compose(service_name, image, ports, volumes)
save_to_file(docker_compose_content)