|
1 |
| -# Pico |
2 |
| - |
3 |
| -_The little git robot of automation!_ |
4 |
| - |
5 |
| -[](https://travis-ci.org/picostack/pico) |
6 |
| - |
7 |
| -Pico is a git-driven task runner to automate the application of configs. |
8 |
| - |
9 |
| -## Overview |
10 |
| - |
11 |
| -Pico is a little tool for implementing [Git-Ops][git-ops] in single-server environments. It's analogous to |
12 |
| -[kube-applier][kube-applier], [Terraform][terraform], [Ansible][ansible] but for automating lone servers that do not |
13 |
| -need cluster-level orchestration. |
14 |
| - |
15 |
| -Instead, Pico aims to be extremely simple. You give it some Git repositories and tell it to run commands when those |
16 |
| -Git repositories receive commits and that's about it. It also provides a way of safely passing in credentials from |
17 |
| -[Hashicorp's Vault][vault]. |
18 |
| - |
19 |
| -## Install |
20 |
| - |
21 |
| -### Linux |
22 |
| - |
23 |
| -```sh |
24 |
| -curl -s https://raw.githubusercontent.com/picostack/pico/master/install.sh | bash |
25 |
| -``` |
26 |
| - |
27 |
| -Or via Docker: |
28 |
| - |
29 |
| -```sh |
30 |
| -docker pull picostack/pico:v1 |
31 |
| -``` |
32 |
| - |
33 |
| -See the docker section below and the image on [Docker Hub](https://hub.docker.com/r/picostack/pico). |
34 |
| - |
35 |
| -### Everything Else |
36 |
| - |
37 |
| -It's primarily a server side tool aimed at Linux servers, so there aren't any install scripts for other platforms. Most |
38 |
| -Windows/Mac usage is probably just local testing so just use `go get` for these use-cases. |
39 |
| - |
40 |
| -## Usage |
41 |
| - |
42 |
| -Currently, Pico has a single command: `run` and it takes a single parameter: a Git URL. This Git URL defines the |
43 |
| -"Config Repo" which contains Pico configuration files. These configuration files declare where Pico can find |
44 |
| -"Target Repos" which are the repos that contain all the stuff you want to automate. The reason Pico is designed |
45 |
| -this way instead of just using the target repos to define what Pico should do is 1. to consolidate Pico config |
46 |
| -into one place, 2. separate the config of the tools from the applications and 3. keep your target repos clean. |
47 |
| - |
48 |
| -Pico also has a Docker image - see below for docker-specific information. |
49 |
| - |
50 |
| -### Configuration |
51 |
| - |
52 |
| -The precursor to Pico used JSON for configuration, this was fine for simple tasks but the ability to provide a |
53 |
| -little bit of logic and variables for repetitive configurations is very helpful. Inspired by [StackExchange's |
54 |
| -dnscontrol][dnscontrol], Pico uses JavaScript files as configuration. This provides a JSON-like environment with |
55 |
| -the added benefit of conditional logic. |
56 |
| - |
57 |
| -Here's a simple example of a configuration that should exist in the Pico config repo that re-deploys a Docker |
58 |
| -Compose stack whenever it changes: |
59 |
| - |
60 |
| -```js |
61 |
| -T({ |
62 |
| - name: "my_app", |
63 |
| - url : "[email protected]:username/my-docker-compose-project", |
64 |
| - branch: "prod", |
65 |
| - up: ["docker-compose", "up", "-d"], |
66 |
| - down: ["docker-compose", "down"] |
67 |
| -}); |
68 |
| -``` |
69 |
| - |
70 |
| -#### The `T` Function |
71 |
| - |
72 |
| -The `T` function declares a "Target" which is essentially a Git repository. In this example, the repository |
73 |
| -`[email protected]:username/my-docker-compose-project` would contain a `docker-compose.yml` file for some application |
74 |
| -stack. Every time you make a change to this file and push it, Pico will pull the new version and run the command |
75 |
| -defined in the `up` attribute of the target, which is `docker-compose up -d`. |
76 |
| - |
77 |
| -You can put as many target declarations as you want in the config file, and as many config files as you want in the |
78 |
| -config repo. You can also use variables to cut down on repeated things: |
79 |
| - |
80 |
| -```js |
81 |
| -var GIT_HOST = "[email protected]:username/"; |
82 |
| -T({ |
83 |
| - name: "my_app", |
84 |
| - url: GIT_HOST + "my-docker-compose-project", |
85 |
| - up: ["docker-compose", "up", "-d"] |
86 |
| -}); |
87 |
| -``` |
88 |
| - |
89 |
| -Or, if you have a ton of Docker Compose projects and they all live on the same Git host, why not declare a function that |
90 |
| -does all the hard work: |
91 |
| - |
92 |
| -```js |
93 |
| -var GIT_HOST = "[email protected]:username/"; |
94 |
| - |
95 |
| -function Compose(name) { |
96 |
| - return { |
97 |
| - name: name, |
98 |
| - url: GIT_HOST + name, |
99 |
| - up: ["docker-compose", "up", "-d"] |
100 |
| - }; |
101 |
| -} |
102 |
| - |
103 |
| -T(Compose("homepage")); |
104 |
| -T(Compose("todo-app")); |
105 |
| -T(Compose("world-domination-scheme")); |
106 |
| -``` |
107 |
| - |
108 |
| -The object passed to the `T` function accepts the following keys: |
109 |
| - |
110 |
| -- `name`: The name of the target |
111 |
| -- `url`: The Git URL (ssh or https) |
112 |
| -- `up`: The command to run on first-run and on changes |
113 |
| -- `down`: The command to run when the target is removed |
114 |
| -- `env`: Environment variables to pass to the target |
115 |
| - |
116 |
| -#### The `E` Function |
117 |
| - |
118 |
| -The only other function available in the configuration runtime is `E`, this declares an environment variable that will |
119 |
| -be passed to the `up` and `down` commands for all targets. |
120 |
| - |
121 |
| -For example: |
122 |
| - |
123 |
| -```js |
124 |
| -E("MOUNT_POINT", "/data"); |
125 |
| -T({ name: "postgres", url: "...", up: "docker-compose", "up", "-d" }); |
126 |
| -``` |
127 |
| - |
128 |
| -This would pass the environment variable `MOUNT_POINT=/data` to the `docker-compose` invocation. This is useful if you |
129 |
| -have a bunch of compose configs that all mount data to some path on the machine, you then use |
130 |
| -`${MOUNT_POINT}/postgres:/var/lib/postgres/data` as a volume declaration in your `docker-compose.yml`. |
131 |
| - |
132 |
| -## Usage as a Docker Container |
133 |
| - |
134 |
| -See the `docker-compose.yml` file for an example and read below for details. |
135 |
| - |
136 |
| -You can run Pico as a Docker container. If you're using it to deploy Docker containers via compose, this makes the |
137 |
| -most sense. This is quite simple and is best done by writing a Docker Compose configuration for Pico in order to |
138 |
| -bootstrap your deployment. |
139 |
| - |
140 |
| -The Pico image is built on the `docker/compose` image, since most use-cases will use Docker or Compose to deploy |
141 |
| -services. This means you must mount the Docker API socket into the container, just like Portainer or cAdvisor or any of |
142 |
| -the other Docker tools that also run inside a container. |
143 |
| - |
144 |
| -The socket is located by default at `/var/run/docker.sock` and the `docker/compose` image expects this path too, so you |
145 |
| -just need to add a volume mount to your compose that specifies `/var/run/docker.sock:/var/run/docker.sock`. |
146 |
| - |
147 |
| -Another minor detail you should know is that Pico exposes a `HOSTNAME` variable for the configuration script. |
148 |
| -However, when in a container, this hostname is a randomised string such as `b50fa67783ad`. This means, if your |
149 |
| -configuration performs checks such as `if (HOSTNAME === 'server031')`, this won't work. To resolve this, Pico will |
150 |
| -attempt to read the environment variable `HOSTNAME` and use that instead of using `/etc/hostname`. |
151 |
| - |
152 |
| -This means, you can bootstrap a Pico deployment with only two variables: |
153 |
| - |
154 |
| -```env |
155 |
| -VAULT_TOKEN=abcxyz |
156 |
| -HOSTNAME=server012 |
157 |
| -``` |
158 |
| - |
159 |
| -### Docker Compose and `./` in Container Volume Mounts |
160 |
| - |
161 |
| -Another caveat to running Pico in a container to execute `docker-compose` is the container filesystem will not |
162 |
| -match the host filesystem paths. |
163 |
| - |
164 |
| -If you mount directories from your repository - a common strategy for versioning configuration - `./` will be expanded |
165 |
| -by Docker compose running inside the container, but this path may not be valid in the context of the Docker daemon, |
166 |
| -which will be running on the host. |
167 |
| - |
168 |
| -The solution to this is both `DIRECTORY: "/cache"` and `/cache:/cache`: as long as the path used in the container also |
169 |
| -exists on the host, Docker compose will expand `./` to the same path as the host and everything will work fine. |
170 |
| - |
171 |
| -This also means your config and target configurations will be persisted on the host's filesystem. |
172 |
| - |
173 |
| -<!-- Links --> |
174 |
| - |
175 |
| -[wadsworth]: https://i.imgur.com/RCYbkiq.png |
176 |
| -[git-ops]: https://www.weave.works/blog/gitops-operations-by-pull-request |
177 |
| -[kube-applier]: https://github.com/box/kube-applier |
178 |
| -[terraform]: https://terraform.io |
179 |
| -[ansible]: https://ansible.com |
180 |
| -[vault]: https://vaultproject.io |
181 |
| -[dnscontrol]: https://stackexchange.github.io/dnscontrol/ |
| 1 | +<p align="center"> |
| 2 | + <a aria-label="Pico logo" href="https://pico.sh"> |
| 3 | + <img src="https://pico.sh/img/pico-wordmark-1000.png" width="420" /> |
| 4 | + </a> |
| 5 | +</p> |
| 6 | + |
| 7 | +<p align="center"> |
| 8 | + <em>The little git robot of automation!</em> |
| 9 | +</p> |
| 10 | + |
| 11 | +<p align="center"> |
| 12 | + <img |
| 13 | + alt="GitHub Workflow Status" |
| 14 | + src="https://img.shields.io/github/workflow/status/picostack/pico/Test?style=for-the-badge" |
| 15 | + /> |
| 16 | + <img |
| 17 | + alt="License" |
| 18 | + src="https://img.shields.io/github/license/picostack/pico?style=for-the-badge" |
| 19 | + /> |
| 20 | +</p> |
| 21 | + |
| 22 | +<p align="center"> |
| 23 | + Pico is a Git-driven task runner built to facilitate GitOps and |
| 24 | + Infrastructure-as-Code while securely passing secrets to tasks. |
| 25 | +</p> |
| 26 | + |
| 27 | +<p align="center"> |
| 28 | + <a href="https://pico.sh">pico.sh</a> |
| 29 | +</p> |
0 commit comments