Fly is written in Bash, for now, because it's a convenient language for quick prototyping. When I get some time, it will be rewritten in Python, probably using Hug.
- Docker Compose
- SQLite
# Create a project.
$ fly project create MyProject /var/www/myproject
# Add services.
$ fly service create MyProject mysql bitnami/apache:latest redis php:5.6-alpine
# Set MySQL root password as environment variable.
$ fly container set MyProject mysql MYSQL_ROOT_PASSWORD root
# Run your services.
$ fly project up MyProject
# After you're done, always bring down your services.
$ fly project down MyProject
# fly project create <unique-project-name> <project-path>
$ fly project create MyProject /var/www/myproject
This will create the dir if it doesn't, exist, along with a .fly/
dir.
It will also create an entry in Fly's database mapping the unique-project-name to the project-path.
$ fly project list
This will list all projects.
A service will run in a Docker container. A service can list another as a dependency. For example, you can define a service named angular
and it can have apache
, mysql
and redis
as a dependency.
If we know the names of the images we want, we can go ahead and add them. If we are unaware of what images exist, we can list them:
$ fly service list
This displays all available services in the format <hub-user>/<repo-name>
The format is the same as it appears on Dockerhub.
We can also search for services:
# fly service search <image-name>
$ fly service search apac*
This will search for services that contain the apach*
regexp pattern.
Once we know what services we want to add to MyProject, we can go ahead and add them:
# fly service create <unique-project-name> <image-name>...
$ fly service create MyProject \
mysql \
bitnami/apache:latest \
redis \
php:5.6-alpine
NOTE: This is the equivalent of manually creating a
docker-compose.yml
file.
This will create a service named myproject
and create dependency services that use the following images:
- mysql
- bitnami/apache:latest
- redis
- php:5.6-alpine
NOTE:
redis
andphp
have no<hub-user>
component. In such cases, we will assume these are the official images.
Now, when the myproject
is started, the added services will begin automatically since they are dependencies.
This command would create a ./fly/docker-compose.yml
file like this:
version: '2'
services:
myproject:
image: tianon/true
depends_on:
- mysql
- bitnami.apache.latest
- redis
- php.5.6-alpine
mysql:
image: mysql
env_file:
- /var/www/myproject/.fly/mysql.env
bitnami.apache.latest:
image: bitnami/apache:latest
env_file:
- /var/www/myproject/.fly/bitnami.apache.latest.env
redis:
image: redis
env_file:
- /var/www/myproject/.fly/redis.env
php.5.6-alpine:
image: php:5.6-alpine
env_file:
- /var/www/myproject/.fly/php.5.6-alpine.env
We might change the way this works using the Docker Extends feature: https://docs.docker.com/compose/extends/
There are two types of environment variables:
- Native Fly Variables.
- Container Variables.
These environment variables are prefixed with FLY
and are used for variable substitution in docker-compose.yml
.
These variables should be stored in .fly/fly.env
in the projects root dir and it should be sourced before running docker-compose up
so that it's a Linux shell environment variable visible via the Linux env
command.
These are environment variables required by the container such as the MYSQL_ROOT_PASSWORD
for the MySQL image.
Also, in terms of security, it's not ideal to store passwords in text files. Ideally, the passwords would be an environment variable that your code would grab and use in your code. When we deploy out app to production, this is the desired practice we'd want. To simulate this real life situation, we can use Container Variables in our app contaner, during development, while keeping our host environment clean.
These variables should probably be stored in .fly/<service-name>.env
in the projects root dir.
Some images like the official MySQL image requires a Container Variable to be set, such as MYSQL_ROOT_PASSWORD
. If this variable is not available to the MySQL container, it will not run.
The user is expected to understand the image requirements which they can do by reading the image documentation on Docker Hub.
We can set this Container Variables like this:
# fly container set <unique-project-name> <image-name> <container-env> <value>
$ fly container set MyProject mysql MYSQL_ROOT_PASSWORD root
That will set MYSQL_ROOT_PASSWORD=root
in .fly/mysql.env
and will be used in creation of the container.
NOTE: This variable can be overwritten as many times as you want which is why I'm using
set
as opposed tocreate
(and thereforeupdate
).
We can also read a variable with:
$ fly container get MyProject mysql MYSQL_ROOT_PASSWORD
We can also search for variables.
The MySQL container also allows you to place an SQL file in a directory and if you mount that directory to /docker-entrypoint-initdb.d
of the container, that SQL file will be imported into the database.
You can also mount a directory from your host machine to /var/lib/mysql
so that the containers MySQL data files state will be saved on your host machine so that the data is not lost on exit of the container.
To make use of this feature, we have to set our service options which will be used in the docker-compose.yml
file.
# fly service set [<hub-user>/]<repo-name> <compose-directive> <value>
$ fly service set mysql volumes /var/www/myproject/database/data:/var/lib/mysql
$ fly service set mysql volumes /var/www/myproject/database/dump:/docker-entrypoint-initdb.d
NOTE: In the above command,
<compose-directive>
can be any value allowed in thedocker-compose.yml
file that is listed in this page: https://docs.docker.com/compose/compose-file/#/volumes-volume-driverFly will have to understand where the command belongs (like, if it's a nested directive like
context
ordockerfile
) and add it accordingly.
The above commands will create the appropriate entries in .fly/fly.env
and in docker-compose.yml
. Prior to execution of the myproject
service, this file will be sourced so that it's available as an environment variable in the host and variable substitution will occur in the docker-compose.yml
file.
Once we have everything ready to go, we just have to bring our containers up:
# fly project up <unique-project-name>
$ fly project up MyProject
NOTE: This is the equivalent of running
docker-compose up
.
After you're done working on that project, you should always bring down your services:
# fly project down <unique-project-name>
$ fly project down MyProject
NOTE: This is the equivalent of running
docker-compose down
.