Services Deployment Manifests
Declarative file format to store information about which services and services versions to be deployed in every environment.
This RFC does not cover deployment of libraries, documentation, or OS packages. Only services.
Problem Description
Deployment is used with the meaning: "the act of upgrading the docker image of an existing service, to use a new docker tag".
We need to do deployments in a way that can be tracked for historical information and authorship, and that allows for future automatic checks.
Background
Actual process to deploy usually involves hooking a jenkins process to a git tag trigger, and then use the commit id to deploy the service. Usually, the git tag name is a semver.
This approach can only work well if only one service exists in one repository, or it needs a bit of hacking to extend it to support more. Even further, using this tangential versioning tool, we are losing the possibilities a versioned file can bring us: traceability of the changes, peer review, reproducibility, testability,...
Also, we would like to have the ability to do a rollback that is not a new deployment of a reverted code change.
Lastly, using manifests to store version related information can bring us a lot of new possibilities: runtime dependency management, digest checking, parallel co-existence of different versions, etc. That options will be extensions of this RFC, or even new RFCs.
In Ebury, some previous efforts are being made to store version information of the released services in files. The repository platform-manifest is a good example on how we already use manifests to store desired version of the services. Some ideas are taken from it, that could be eventually be ported to this new RFC.
Solution
Repositories may contain a directory, not necessarily at root-level, called environments with sub-directories named after deployment environments to be used. Most common environments are prod and devel.
Every environment directory then contains at least a manifest.json file to reflect the desired status of a list of services. The content of the file must be standard json, and the root element must be a json object, i.e. a dict.
This object, the manifest onwards, has the following keys:
services: an optional list with the services, each service being a dict with:
name: the name of the serviceversion: optional, a semver (reserved to mark dependencies between services)containers: optional, a list with the containers that represent every instance of the service. Each container will have:dockerName: optional, the docker name of the image to deploy (if empty: the same than the service)dockerTag: the docker tag to deploydockerDigest: optional, the docker sha256 digest of the docker image (reserved to express a desired check in a future modification of this RFC)
includes: an optional list of strings, each one being a relative path from the manifest itself. The content of that files will be imported, so their content of the services list will be considered with the same effect that if prepended to the one in the current file. They will be processed in the order they appear. They will be able to have its own includes section. With this option, you can have a master manifest that include others, and you can manage them in one or in several repositories depending on the scenario.
The convention includes a consideration about the name of the files. If a repository in ebury shares the name with a manifest, then this repository can be considered the reference for the file. Example: if a file ebury-api-events.json is imported, it is sure that the services there are built using the repository ebury-api-events. This has been useful to allow repositories to trigger devel deployments. The pipeline just needs to upgrade the owned file in the manifests repository.
skipConfirmation: optional boolean, false by default. Will be taken into account only for the root manifest. If true, the process will not ask for confirmation before upgrading services, and will just execute the deployments. It has been used in the non production environments.
For example, the file environments/devel/manifest.json of a repository can look like this:
{
"includes": [
"./other.json",
"./files.json"
],
"services": [
{
"name": "events-logger",
"version": "0.1.0",
"containers": [
{
"dockerTag": "e96ae0a",
"dockerDigest": "sha256:f48a20f48cbc2b965e37ff9144048c644890cb37cefa85fafc8fae7f89b15455"
}
]
},
{
"name": "events-beat",
"version": "0.1.0",
"containers": [
{
"dockerTag": "e96ae0a",
"dockerDigest": "sha256:499442b8120888f3dddefe40f8a771ac252b2fd03b5efa122f61dd5bbfb32352"
}
]
}
]
}
It is important to clarify that this RFC states how these files can be arranged to express the desired status of the services deployment. The actual process to build images, publish them on some registries, and then get these docker images into the services orchestrator is not covered by this RFC. Even more, while this RFC is not going to dictate the repositories structure, it is encouraged that repositories that contain manifests do not contain code for services or libraries, sinde the life cycle of deployments are intended to be separated from the code life cycle.
Changes into manifests can get into the master branch by any mean, but preferably they will land after proper pull requests. These PRs can be created by hand, or automatically as the outcome of some automatic process, webhook, or pipeline. For example, a new commit in the repository ebury-example, master branch, can create automatically a PR in the repo ebury-example-manifests with the changes proposed to deploy the services in the devel environment. After that, the operator can review the PR, get it approved, and then expect that the devel environment will eventually have the desired state.
This process assumes we can get a single docker image based on the name and the tag, and that the rest of information (like the registry location, the credentials,...) will be configuration on the actual implementation. The schema to select docker tags used is also not specified in the document.
Alternatives
The git tag alternative that is in use is considered, and the problems identified are stated in the Background section.
Caveats
The content of every manifest.json can be extended in future RFCs. Do not use these files with extra keys without proposing a change into this RFC first, or at least do it at your own risk. You can consider the environments/*/manifest.json files of every repository must follow the rules stated in this (and future complementary) RFCs.
Operation
The actual operation to execute the manifest file is not covered by the RFC.
We will link here the existing/recommended implementations when ongoing experiments got merged upstream in jenkins-devops repository.
Security Impact
The RFC covers a declarative JSON that cannot derivate into any security problem.
The implementations will need to take into account a proper mechanism to request authorization to proceed, every time a reconciliation of the state is needed.
Performance Impact
N/A
Developer Impact
The developer will have a better understanding on how services are deployed and will be able to follow the history of deployments using git log on this environments directory.
Deployment
This RFC is about deploying other services. It does not need to be deployed itself.
Dependencies
No dependencies found.
Informal dependencies are that we are assuming every service is packaged as a docker image.
References
No references.