{"id":22973833,"url":"https://github.com/get-bridge/muss","last_synced_at":"2025-07-17T12:38:57.286Z","repository":{"id":39127869,"uuid":"228451551","full_name":"get-bridge/muss","owner":"get-bridge","description":"For when your docker-compose projects are a mess","archived":false,"fork":false,"pushed_at":"2023-12-18T22:41:36.000Z","size":346,"stargazers_count":5,"open_issues_count":13,"forks_count":2,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-02T00:35:51.825Z","etag":null,"topics":["internal"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/get-bridge.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2019-12-16T18:39:16.000Z","updated_at":"2023-04-20T17:24:07.000Z","dependencies_parsed_at":"2024-02-28T02:27:28.420Z","dependency_job_id":null,"html_url":"https://github.com/get-bridge/muss","commit_stats":{"total_commits":110,"total_committers":10,"mean_commits":11.0,"dds":"0.19090909090909092","last_synced_commit":"bf280d8e76a4ceec5219e0da5a9b89299ed3c7ef"},"previous_names":["instructure-bridge/muss"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/get-bridge/muss","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/get-bridge%2Fmuss","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/get-bridge%2Fmuss/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/get-bridge%2Fmuss/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/get-bridge%2Fmuss/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/get-bridge","download_url":"https://codeload.github.com/get-bridge/muss/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/get-bridge%2Fmuss/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265607203,"owners_count":23797093,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["internal"],"created_at":"2024-12-14T23:58:57.833Z","updated_at":"2025-07-17T12:38:57.268Z","avatar_url":"https://github.com/get-bridge.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/instructure/muss.svg?branch=master)](https://travis-ci.org/instructure/muss)\n\n# muss\n\nDefinition:\n\n\u003e noun: mess; scramble; a confused conflict\n\u003e verb: to put into disorder; to make messy\n\nOr if you prefer, an acronym:\n\n\u003e Manage User Selected Services\n\n`muss` is a command line application to allow users to choose what services\nthey want to run and how they want to run them.\n\n`muss` is a wrapper around `docker-compose`.\nWhen you run a `muss` subcommand it will:\n\n- process (and validate) the config files\n- generate a `docker-compose.yml`\n- prepare any defined bind mounts (volumes)\n- load secrets into the environment\n- delegate to `docker-compose`\n\nProjects (and their dependent services) can be configured\nin a familiar style through a series of yaml files.\n\n\n# Installation\n\n    brew tap instructure/muss\n    brew install muss\n\n\n# Building, Testing, etc\n\n`muss` is a CLI written in go.\n\n`make install` to install it into your `$GOPATH`.\n\nYou can use `make test` to test all of the included go packages\nor you can run any `go` commands directly (`go test ./cmd`).\n\n\n# Usage\n\n`muss help` will describe available subcommands.\n\nMany docker-compose commands are supported directly\nso that config files are always up to date and secrets\nare loaded into the environment.\n\nThe simplest possible usage is to call `muss up`\nto start all the services and type Ctrl-C to shut it down.\n\n    $ muss help\n    Configure and run project services\n\n    Usage:\n      muss [command]\n\n    Available Commands:\n      attach      Attach local stdio to a running container\n      build       Build or rebuild services\n      config      muss configuration\n      dc          Call aribtrary docker-compose commands\n      down        Stop and remove containers, networks, images, and volumes\n      exec        Execute a command in a running container\n      help        Help about any command\n      logs        View output from services\n      ps          List containers\n      pull        Pull the latest images for services\n      restart     Restart services\n      rm          Remove stopped containers\n      run         Run a one-off command\n      start       Start services\n      stop        Stop services\n      up          Create and start containers\n      version     Show version information\n      wrap        Execute arbitrary commands\n\n    Flags:\n      -h, --help   help for muss\n\n    Use \"muss [command] --help\" for more information about a command.\n\n## Advanced Usage\n\nFor less common docker-compose commands that muss does not define\nyou can use the `dc` subcommand, e.g. `muss dc events --json`.\n\nYou can also run any arbitrary commands using `muss wrap`.\nThis allows you to run a command after files have been generated and\nthe environment has been loaded.\n\nmuss has its own `config` subcommand (different from the docker-compose\nconfig command).\n\n`muss config save` will generate the files.  This happens before running other\ncommands (like `muss up`) but this can be useful if you just want to inspect the\nfiles.\n\n`muss config show` will print out the whole configuration.  The `--format`\nparameter takes a go template string to allow you to limit or manipulate the\nconfig (useful for scripting and debugging).\n\n\n# Configuration\n\nA muss project is configured via a series of yaml files:\n\n1. project config\n2. user config\n3. module definitions\n\nThe project configuration defines:\n\n- default preferences for module configs\n- secret commands\n- status command\n- the locations of additional config files\n- docker-compose settings\n\nThis file should be committed into source control.\n\n\nA muss user file allows you to specify preferences and customizations:\n\n- specify a different module order than the project's default\n- select specific module configs\n- disable modules that you don't intend to use\n- a compose override map to be merged in at the end\n\nThis file should be ignored by version control.\n\n\nThe project file can include the location of module definition files,\neach of which:\n\n- has a name\n- defines one or more config options for how to run the service\n  (example use cases would be local repos, pre-baked docker images,\n  or remote services).\n\n\n## Project Config\n\nThe syntax and options for the main `muss.yaml` file:\n\n```yaml\n    ---\n    # Path to user customization file.\n    user_file: muss.user.yaml\n\n    # If present will set COMPOSE_PROJECT_NAME (unless already set).\n    project_name: myproject\n\n    # Alternate target for compose config (default is docker-compose.yml).\n    # If present will set COMPOSE_FILE (unless already set).\n    # Note that when COMPOSE_FILE is set docker-compose will not automatically\n    # use docker-compose.override.yml.\n    # The override section of the muss user file will still work, however.\n    compose_file: \"docker-compose.muss.yml\"\n\n    # Define the order of which configuration option to use\n    # for any module that has multiple options.\n    default_module_order:\n      - registry\n      - repo\n      - internal\n\n    # Module files are yaml files containing module definitions.\n    module_files:\n      - ./dev/database.yml\n      - ./dev/microservice/service.yml\n\n    # Secret commands define aliases that can be used by module definitions.\n    secret_commands:\n      vault:\n\n        # Arguments will be prepended to the secret arguments.\n        exec: [\"vault\", \"kv\", \"get\", \"-field\"]\n\n        # Env Commands will be run once to setup the environment\n        # if any secrets are requested.\n        env_commands:\n          # When you specify a varname the output of the command\n          # will be set in that environment variable.  If that variable\n          # is already set in the environment the command will not be run.\n          - varname: VAULT_TOKEN\n            exec: [\"bin/vault-token\"]\n\n    # A passphrase is required for local caching of the secrets.\n    # Use an env var representing your auth token.\n    secret_passphrase: $VAULT_TOKEN\n\n    # A status line will be fixed to the bottom of the screen during \"up\".\n    status:\n      # Stdout from this command will appear in the status line.\n      exec: [\"bin/muss-status\"]\n      # Each line of status output will be formatted with this spec:\n      line_format: \"# %s\"\n      # Specify how often to execute the command to update the status:\n      interval: 5s\n```\n\n\n## User Config\n\nUsers can customize what they want to run with a user file:\n\n```yaml\n    ---\n    # Users can set their own order for which module config to use.\n    # This list will be used before the default_module_order of the\n    # project config.\n    module_order:\n      - remote\n      - repo\n\n    # Modules can also be chosen specifically (to override order lists)\n    modules:\n      microservice:\n        config: remote\n\n      # ...or removed completely.\n      stats:\n        disabled: true\n\n    # An override section can be defined that will be merged onto the\n    # docker-compose config.  By defining it here, muss extensions (like file\n    # volumes) can be utilized.\n    override:\n      services:\n        app:\n          environment:\n            HOW_I_LIKE_IT: nifty\n```\n\n\n## Module Definitions\n\nModule files contain module definitions that will generate chunks of a\ndocker-compose file (which will all be merged on top of each other).\n\nA module can define multiple configs.\nThe names of the configs are arbitrary;\nThese are the values used in the\n`module_order` and `default_module_order` lists.\nUse common names among your modules so that the\norder options apply as consistently as possible.\n\nIn the example below:\n- \"local\" implies \"run from local directory\"\n- \"registry\" implies \"an image from a docker registry\"\n- \"edge\" and \"staging\" are different options for external integrations\n\nWhen multiple configs are defined\nthe option will be chosen in this order:\n- `MUSS_MODULE_ORDER` env var (split on commas)\n- a specific user choice\n- the first of any `module_order`\n- the first of any `default_module_order`\n\nThe body of a module config can contain the following:\n- \"include\" is a list of items to merge in before the rest of the map\nand can be:\n  - a string referring to another config name\n  - a map of `file: path` to read in a file (relative to muss.yaml)\n- \"secrets\" is a list of secrets to load\n- \"services\" is a subset of the \"services\" section of a docker-compose\n  configuration... it will be passed through.\n- \"volumes\" is also just a piece of docker-compose syntax that will be passed.\n\n\n```yaml\n    ---\n    # Module name.\n    name: microservice\n\n    configs:\n\n      # Configs with a leading underscore are private/internal\n      # and can be used as common bases for merging.\n      _base:\n\n        # The \"services\" map will be merged into the final docker-compose yaml.\n        # We define attributes of multiple services here that will all be merged\n        # on top of each other (the way a docker-compose override file works).\n        services:\n          app:\n            environment:\n              # The \"app\" service (defined more fully elsewhere)\n              # will only receive this environment variable\n              # if this service definition is enabled.\n              MICROSERVICE_ENABLED: '1'\n          microservice:\n            environment:\n              APP_ENV: 'development'\n\n      local:\n        include:\n          # A config can start by including other maps that will be merged in first.\n          # This can be the name of another config\n          - _base\n          # or the contents of another yaml file.\n          - file: compose-snippet.yml\n\n        # Any \"volumes\" will also pass to docker-compose.\n        volumes:\n          microservice-data: {}\n        services:\n          microservice:\n            # Paths will be relative to the project root.\n            build: ../microservice\n            volumes:\n              - microservice-data:/var/lib/microservice\n\n      registry:\n        include:\n          - _base\n        services:\n          microservice:\n            image: our-registry/microservice\n\n      _remote:\n        services:\n          # This service can define how another service will reach it.\n          app:\n            environment:\n              MICROSERVICE_URL:\n              MICROSERVICE_KEY:\n          # Note that there is no \"microservice\" here.\n          # By pointing to a remote instance\n          # we have eliminated the need to run it locally.\n\n      edge:\n        include:\n          - _base\n          - _remote\n        # A config can define secrets that will be loaded into the environment.\n        secrets:\n          MICROSERVICE_URL: {vault: [\"MICROSERVICE_URL\", \"app/edge/common\"]}\n          MICROSERVICE_KEY: {vault: [\"MICROSERVICE_KEY\", \"app/edge/common\"]}\n\n      staging:\n        include:\n          - _base\n          - _remote\n        secrets:\n          MICROSERVICE_URL: {vault: [\"MICROSERVICE_URL\", \"app/staging/common\"]}\n          MICROSERVICE_KEY: {vault: [\"MICROSERVICE_KEY\", \"app/staging/common\"]}\n```\n\nAny \"services\" defined that do not contain a \"build\" or an \"image\" will not be\nincluded in the final docker-compose file.  This allows one service to define\nwhat secrets are available for another service even if that service won't be\nused in the end.\n\nService integration can now be organized around how services will be selected.\nAll of the docker-compose configuration for a given service can be placed in the\nsame module file, including not only that service (or multiple services)\nbut also how it integrates with another service.\n\nFor example, if a microservice can be local, remote, or completely optional,\nthe definition file can point the environment variables for other services\nto this one.  That way they update according to which ever option is chosen,\nor the service can be completely disabled and the other services won't receive\nthe environment variables at all.\n\nAs another example, you could have a stats container that collects and prints\nstats from all other services.  If the stats service file defines not only the\nstats service but also the environment variables for all the other services\nthat will send stats to it, then you can simply disable the stats service\nfrom your user config file and all the other services will no longer be\nconfigured to send any stats.\n\n\n# Secrets\n\nModule definitions can specify secrets to be loaded by external commands.\n\nThe project configuration defines aliases that simplify the usage\nand define commands that setup the environment\n(for example, logging in to vault and returning the token).\n\nWhen a module config is chosen that includes secrets:\n\n- the setup commands are executed and the environment is populated\n- the individual secret commands are then run and added as environment variables\n- muss then delegates to the subcommand (docker-compose, etc).\n\nSecrets are cached and encrypted with the `secret_passphrase`.\nSo if you use your auth token as your passphrase the secrets will be cached\nfor as long as your token is valid.  When you get a new token it will force\nfetching new secrets.\n\nSecret commands can either specify a `varname` and the STDOUT of the script\nwill be assigned to that var.\nAlternatively the commands can specify: `parse: true`\nand the output will be parsed as lines of `NAME=VALUE`.\n\nSTDIN and STDERR will pass directly so that users can response to password\nprompts and see errors.\n\nTo provide a more concrete example:\n\n`muss.yaml`:\n\n    secret_commands:\n      vault:\n        exec: [\"vault\", \"kv\", \"get\", \"-field\"]\n        env_commands:\n          - exec: [\"bin/vault-token\"]\n            parse: true\n        # The passphrase will be parsed and env vars will be interpolated.\n        passphrase: $VAULT_TOKEN\n        # The \"cache\" value can be \"passphrase\" (the default)\n        # \"none\" to disable caching, or a duration (\"24h\", \"168h\")\n        # to expire the cache (if the passphrase hasn't already changed by then).\n        cache: \"passphrase\"\n    # You can set a global passphrase that will be used for any secrets\n    # that do not define their own.\n    secret_passphrase: $VAULT_TOKEN\n    module_files:\n      - dev/microservice.yml\n\nThe exec command can be something global\nbut will often be a command that is part of your project.\n\nThe `bin/vault-token` script would probably do something like this:\n\n    #!/bin/bash\n\n    # Setup any necessary env like (perhaps VAULT_ADDR).\n    export VAULT_ADDR=...\n\n    if ! token-is-valid; then\n      vault login ...\n      # persist the token and expiration so that next time\n      # the script runs it won't have to login again.\n    fi\n\n    # These lines will be parsed and set in the environment.\n    echo VAULT_ADDR=\"$VAULT_ADDR\"\n    echo VAULT_TOKEN=\"$(\u003c ~/.vault-token )\"\n\nThe actual secrets in the module definition (`dev/microservice.yml`):\n\n    name: microservice\n    configs:\n      somewhere-far:\n        secrets:\n          SECRET_KEY: {vault: [\"MICROSERVICE_KEY\", \"path/to/key\"]}\n        services:\n          app:\n            environment:\n              SECRET_KEY: # no value, it will get it from the environment.\n\nSo when the \"somewhere-far\" option is chosen for the module\nit will load those secrets.\n\nFirst `bin/vault-token` will be executed and `VAULT_ADDR` and `VAULT_TOKEN`\nwill be set in the environment.\n\nThen `vault kv get -field MICROSERVICE_KEY path/to/key` will be executed\nand the value stored in the `SECRET_KEY` environment variable.\n\nThen muss will continue and delegate to `docker-compose` to run your services\nand the populated environment variables will be passed along.\n\n\n# Additional Behavior\n\nA few additional behaviors are defined beyond the normal docker-compose\nfeatures.\n\n\n## Volumes\n\nWhen bind mounts (host volumes) are specified muss will attempt to ensure\nthat they already exist.  This helps prevent permission problems that can occur\nby letting the docker daemon create a directory under your project directory.\n\n\n## File volumes\n\nAdditionally volumes can be specified to be files instead of directories\nwhich can be useful for mounting config files into the container.\nJust use the long syntax for volumes and add `file: true`:\n\n    volumes:\n      - target: /home/docker/.somerc\n        source: ~/.somerc\n        file: true\n\nThis way if the specified path isn't already a file muss will create it\nso that docker doesn't make it a directory and cause confusing errors later.\n\nThe `file: true` will be removed from the resulting docker-compose file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fget-bridge%2Fmuss","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fget-bridge%2Fmuss","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fget-bridge%2Fmuss/lists"}