pulumi/docs/overview.md
2017-01-26 07:51:46 -08:00

149 lines
9.9 KiB
Markdown

# Mu Overview
Mu is a toolset and runtime for creating reusable cloud services. Mu lets you author packages that can be shared and
consumed just like your favorite programming language's libraries. Mu is inherently multi-language, multi-cloud, and
supports building abstractions that span different cloud environments and topologies.
This document provides an overview of the Mu system, its goals, primary concepts, and the system architecture.
## Problem
Cloud services are complex. They are complex to build, complex to deploy, and complex to manage. The current trend to
use increasingly fine-grained microservices simply exacerbates this complexity, transforming most modern cloud
applications into complex distributed systems.
There are many aspects to building distributed systems that aren't evident to the newcomer -- like RPC, logging,
fault tolerance, and zero-downtime deployments -- and even the experienced practitioner will quickly find that the
developer and operations tools do not guide us down the golden path. Indeed, it is common to need to master a dozen
tools before even getting an application up and running in production.
On top of that complexity, it is difficult to share knowledge. Most modern programming languages have component models
that allow you to bundle up complex functionality underneath simple abstractions, and package managers that allow you
to share these components with others, and consume components shared by others, in the form of libraries. The current
way that cloud architectures are built and deployed is simply not amenable to this kind of sharing.
Even if there was a way to share components, the cloud platforms are divergent in the configuration languages they
accept, infrastructure abstractions that they provide, and the specific knobs used to configure those abstractions. It
is as though every Node.js programmer out there needs to understand the intricate details of the Linux scheduler, versus
macOS, versus Windows, just to deliver a simple web application.
Finally, once such an application is up and running, managing and evolving it requires similarly ad-hoc and
individualized tools and practices. Applying changes to a running environment is often done manually, in a
hard-to-audit way, and patches are applied unevenly and inconsistently, often leaving security problems open to attack.
All of the above is a big productivity drain, negatively impacting the agility of organizations that need to innovate
in service of their businesses. It means that improvements are more costly to deliver. Containers have delivered a
great improvement to the management of single nodes in a cluster, but has not yet expanded that same simplicity to
managing entire applications or entire clusters. Thankfully by adopting concepts and ideas that have worked in the
overall landscape of languages and runtimes, we can make considerable improvements in all of these dimensions.
## Solution
Mu lets developers author components in their language of choice (JavaScript, Python, Ruby, Go, etc). This is in
contrast to most cloud programming models today which require the use of often-obscure configuration languages or DSLs.
This unified view is particularly helpful when building serverless applications where you want to focus on code.
At the same time, Mu is polyglot, allowing composition of components authored in many different languages.
These components can be built by reusing existing components shared by others, and published to the Mu package manager
for others to use. Cloud services are simply instances of these components, with property values configured
appropriately, and change management is done automatically by Mu's understanding of the overall graph of dependencies
between those services. Think of each service as an "object" that is running in the cloud.
Mu runs on any public or private cloud. Although you are free to program directly to your cloud provider's specific
abstractions, Mu also facilitates building more abstract cloud-neutral components that can run anywhere. This includes
compute services, storage services, and even more logical domain-specific services like AI, ML, and recognition.
## Concepts
The primary concepts in Mu are:
* **Stack**: A static description of a topology of cloud services with optional APIs.
* **Package**: A collection of exports stacks for consumption by others.
* **Service**: An instantiation of a stack, grouping zero to many services, together.
* **Cluster**: A hosting environment that stacks can be deployed into, reifying them as services.
* **Workspace**: A static collection of zero to many stacks managed together in a single source repository.
In an analogy with programming languages, a stack is like a *class* and a service is like an *object*. Many concepts
that are "distinct" in other systems, like the notion of gateways, controllers, functions, triggers, and so on, are
expressed as stacks and services in the Mu system. They are essentially "subclasses" -- or specializations -- of this
more general concept, unifying the configuration, provisioning, discovery, and overall management of them.
In addition to those core abstractions, there are some supporting ones:
* **Identity**: A unit of authentication and authorization, governing access to protected resources.
* **Configuration**: A bag of key/value settings used either at build, runtime, or a combination.
* **Secret**: A special kind of key/value configuration bag that is encrypted and protected by identity.
Because Mu is a tool for interacting with existing clouds -- including targets like AWS, Kubernetes, and Docker Swarm --
one of the toolchain's most important jobs is faithfully mapping these abstractions onto "lower level" infrastructure
abstractions, and vice versa. Much of Mu's ability to deliver on its promise of better productivity, sharing, and reuse
relies on its ability to robustly and intuitively perform these translations. There is an extensible provider model for
creating new providers, which amounts to implementing create, read, update, and delete (CRUD) methods per resource type.
## Example
Let us look at an example stack written in Mu's flavor of JavaScript, MuJS:
import * as mu from "mu";
export class Thumbnailer extends mu.Stack {
private source: mu.Bucket; // the source to monitor for images.
private dest: mu.Bucket; // the destination to store thumbnails in.
constructor(source: mu.Bucket, dest: mu.Bucket) {
this.source = source;
this.dest = dest;
this.source.onObjectCreated(async (event) => {
let obj = await event.GetObject();
let thumb = await gm(obj.Data).thumbnail();
await this.dest.PutObject(thumb);
});
}
}
This `Thumbnailer` stack simply accepts two `mu.Bucket`s in its constructor, stores them, and wires up a lambda to run
on the source's `onObjectCreated` event. This program describes a reusable cloud service that can be instantiated any
number of times in any environment. It is important to note that the body of this lambda is real JavaScript, while the
configuration outside of it is the MuJS subset. Mu is letting us mix what would have been classically expressed using a
combination of configuration and real programming languages in one consistent and idiomatic programming model.
Let us now look at an instantiation of `Thumbnailer`. This happens elsewhere in something we call a *blueprint*:
import * as aws from "@mu/aws";
import * as mu from "mu";
import {Thumbnailer} from "...";
let images = new aws.s3.Bucket("images");
let thumbnails = new aws.s3.Bucket("thumbnails");
let thumbnailer = new Thumbnailer(images, thumbnails);
Many Mu programs are libraries, while blueprints are akin to executables in your favorite language.
The `aws.s3.Bucket` class is a subclass of `mu.Bucket`, and so can be passed to `Thumbnailer`'s constructor just fine.
Notice how `Thumbnailer` is itself a cloud-neutral abstraction. Of course, if it had wanted to access specific AWS S3
features, it could have accepted a concrete `aws.s3.Bucket`; as with ordinary object-oriented languages, the
abstraction's author decides (e.g., this is similar to accepting a concrete "list" versus "enumerable" interface).
The Mu toolchain analyzes this program and understands its components. The program isn't run directly; instead, it is
fed into a command like `mu compile`, `mu plan`, and `mu apply`, to determine how to create, update, or delete resources
in a target cluster environment, using resource providers. For instance, running `mu apply` on the above program, in a
new cluster, will create two S3 buckets and a single AWS lambda wired up to the source bucket. If we make edits, and
reapply those edits, just the parts that have been changed will be updated in the target environment.
## Further Reading
More details are left to the respective design documents. Here are some key ones:
* [**Languages**](design/languages.md): An overview of Mu's three languages: MetaMus, MuPack/MuIL, and MuGS.
* [**MuPack/MuIL**](design/mupack.md): A detailed description of Mu's packaging and computation formats.
* [**Stacks**](design/stacks.md): An overview of how stacks are represented using the above fundamentals.
* [**Dependencies**](design/deps.md): An overview of how package management and dependency management works.
* [**Clouds**](design/clouds.md): A description of how Mu abstractions map to different cloud providers.
* [**Runtime**](design/runtime.md): An overview of Mu's runtime footprint and services common to all clouds.
* [**Cross-Cloud**](design/x-cloud.md): A brief description of how Mu can be used to create cloud-neutral abstractions.
* [**Security**](design/security.md): An overview of Mu's security model, including identity and group management.
* [**Resources**](design/resources.md): A description of how extensible resource providers are authored and registered.
* [**FAQ**](faq.md): Frequently asked questions, including how Mu differs from its primary competition.