内容简介:Developers are spoiled.Every single package management system these days will allow a developer to define their project's dependencies in a simple format, whether that's aDeclaring your dependencies and their desired version in a standard, easily-parseable
Developers are spoiled.
Every single package management system these days will allow a developer to define their project's dependencies in a simple format, whether that's a cargo.toml in Rust, Gemfile for Ruby apps, a pom.xml for Maven-based projects, package.json for NodeJS, composer.json in PHP…
Declaring your dependencies and their desired version in a standard, easily-parseable language allows you to track outdated dependencies, make sure you keep up to date with security updates, ensures other developers working on the same project use the same version of dependencies, lets you set up reproducible builds… The benefits are immense, and it's universally acknowledged as a best practice in modern software development.
But when it comes to the subfield of software engineering known as Infrastructure-as-Code (also variously referred to as DevOps, or SRE, but I'll use infrastructure-as-code through this post) though, the alternatives become rare.
It is possible, as most sysadmins are used to, to follow individual projects through mailing lists, or periodically check projects’ websites for new releases and updates. But this doesn't scale well as you add extra dependencies, and is at its core a very manual process.
Chef probably has the most full-featured dependency management system that I've encountered so far, the Chef Supermarket . But it only ensures Chef cookbooks are up-to-date, and only covers the subset of the infrastructure-as-code that Chef will support. What about your cloud orchestration software? What about Chef itself?
Part of the problem is that a modern infrastructure-as-code pipeline will rely on several separate, distinct, pieces of software, depending on which part of the infrastructure is being set up: Terraform , CloudFormation , Chef / Ansible / Puppet , Helm … These incompatible systems are written in different languages and follow different versioning schemes, so an overarching dependency management system isn't easy to come by.
But dependency management is a worthy goal, so let's take a crack at it!
Based on the findings above and lessons from the Kubernetes project's handling of dependencies , I'd like to introduce my attempt at solving this issue: Zeitgeist .
Introducing Zeitgeist
Zeitgeist is a language-agnostic dependency checker.
Zeitgeist will let you define your dependencies in a YAML file, dependencies.yaml
, and help you ensure:
- These dependencies versions are consistent within your project
- These dependencies are up-to-date
The key concept that allows Zeitgeist to be language-independent is that dependencies are declared with a reference to another plain-text file where that dependency is defined for the underlying tool , so any infrastructure-as-code tool that lets you define your dependencies in plain-text will be supported.
For example, let's say you build your infrastructure via Terraform, and use a pinned version of Terraform to create a Docker container that applies your infrastructure in a reproducible fashion. Your Dockerfile may look something like:
FROM alpine:3.10 ENV TERRAFORM_VERSION="0.12.12" RUN curl -LO https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip \ && unzip terraform_${TERRAFORM_VERSION}_linux_amd64.zip \ && mv terraform /bin # Install more tools, etc
You can define this version of Terraform as a dependency:
- name: terraform version: 0.12.12 upstream: flavour: github url: hashicorp/terraform refPaths: - path: Dockerfile match: TERRAFORM_VERSION
The important information for dependency checking here is the refPaths
: path
refers to a file, and match
is a string that will be searched in this file.
Zeitgeist will read the file at path
, searching for a line matching match
, and when found, confirm that the version declared on this line is identical to the version declared in your dependencies.yaml
.
The upstream
block is used to check if your local version is up-to-date with the project it references. Here, Zeitgeist will check the local version against Terraform Releases on Github
, and let you know when an update is available.
You may then define an AMI image
for an AutoScaling group in a Terraform source file
that we'll call my-asg.tf
as:
resource "aws_launch_template" "foobar" { name_prefix = "foobar" image_id = "ami-1a2b3c" instance_type = "t2.micro" } resource "aws_autoscaling_group" "bar" { availability_zones = ["us-east-1a"] desired_capacity = 1 max_size = 1 min_size = 1 launch_template { id = "${aws_launch_template.foobar.id}" version = "$Latest" } }
Now, how do you ensure this AMI stays up to date? What if a new version gets released?
Zeitgeist can also take care of that for you! Define the dependency as:
- name: my-example-ami version: ami-1a2b3c scheme: random upstream: flavour: ami owner: somebody name: "terraform-example-*" refPaths: - path: my-asg.tf match: image_id
And Zeitgeist will let you know when a new version of the AMI is available, based on the owner and a regexp.
Another common issue is when a dependency is used in two different contexts, and these need to be kept in sync. This was the Kubernetes project's most important requirement when implementing their solution, and I've followed the same yaml structure when designing Zeitgeist.
For example, Helm (up to version 3) needs two components:
-
tiller
, the server-side component of Helm, deployed on your Kubernetes cluster -
The
helm
CLI, used locally to interact withtiller
But using different versions of helm
and tiller
will often result in errors
, so it's better to keep them in sync.
This can be expressed as a dependency with two refPaths
:
- name: helm version: 2.12.2 upstream: flavour: github url: helm/helm constraints: <3.0.0 refPaths: - path: bootstrap/tiller.yaml match: gcr.io/kubernetes-helm/tiller - path: helper-image/Dockerfile match: HELM_LATEST_VERSION
And Zeitgeist will ensure these stay in sync with each other, as well as check the upstream for updates.
Working with Zeitgeist
We have introduced Zeitgeist in our infrastructure-as-code pipeline late last year to check dependencies on deployment and give us a nightly dependency report of available updates.
Since then, Zeitgeist has been fulfilling its stated aim of helping us keep our infrastructure up-to-date, but its major benefit in my opinion has been the peace of mind gained by knowing that pinned versions of dependencies are managed , and we don't have to worry about them silently falling behind.
Zeitgeist supports Github, AMIs, and Helm as upstreams for version checking, with more in the pipeline!
How do I use it in my own projects?
To use Zeitgeist in your own project, create a dependencies.yaml
and run the zeitgeist
command-line tool. Pre-build binaries are available on Github
.
Zeitgeist is written in Go and hosted on Github under the Apache 2.0 license. Contributions, bug reports, and feature suggestions are very welcome!
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。