|
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: "git@github.com: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 | | -`git@github.com: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 = "git@github.com: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 = "git@github.com: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