Quick Start¶
Once installed, Fapistrano bootstraps a fap command to complete release/rollback/restart task.
First Run¶
Add a file named deploy.yml:
project_name: smallest-example
app_name: smallest-example
user: deploy
use_ssh_config: true
stage_role_configs:
staging:
app:
hosts:
- app-stag01
After Runing command below, Fapistrano will create a smallest example on your host:
$ fap release --stage staging --role app
[app-stag01] Executing task 'release'
===> Starting
[app-stag01] run: mkdir -p /home/deploy/www/smallest-example/{releases,shared/log}
[app-stag01] run: chmod -R g+w /home/deploy/www/smallest-example/shared
[app-stag01] run: mkdir -p /home/deploy/www/smallest-example/releases/160328-162832
===> Started
===> Updating
===> Updated
===> Publishing
[app-stag01] run: ln -nfs /home/deploy/www/smallest-example/releases/160328-162832 /home/deploy/www/smallest-example/current
===> Published
===> Finishing
[app-stag01] run: ls -x /home/deploy/www/smallest-example/releases
===> Finished
For now, it does nothing but leaving a blank directory hierachy to you:
$ ssh deploy@app-stag01 tree /home/deploy/www/smallest-example/
/home/deploy/www/smallest-example/
├── current -> /home/deploy/www/smallest-example/releases/160328-162832
├── releases
│ └── 160328-162832
└── shared
└── log
5 directories, 0 files
Using Git¶
Git is a popular scm tool. Fapistrano integrated git as a plugin. You need to declare loading fapistrano.git and specify repository in deploy.yml:
project_name: git-example
app_name: git-example
user: deploy
use_ssh_config: true
stage_role_configs:
staging:
app:
hosts:
- app-stag01
plugins:
- fapistrano.plugins.git
repo: git@github.com:octocat/Hello-World.git
branch: master
By Executing release flow, Fapistrano clones remote git repo and export code in master branch to release directory:
$ fap release --stage staging --role app
[app-stag01] Executing task 'release'
===> Starting
[app-stag01] run: mkdir -p /home/deploy/www/git-example/{releases,shared/log}
[app-stag01] run: chmod -R g+w /home/deploy/www/git-example/shared
[app-stag01] run: mkdir -p /home/deploy/www/git-example/releases/160328-163937
===> Started
[app-stag01] run: git clone --mirror --depth 1 --no-single-branch git@github.com:octocat/Hello-World.git /home/deploy/www/git-example/repo
[app-stag01] run: git ls-remote --heads git@github.com:octocat/Hello-World.git
===> Updating
[app-stag01] run: git fetch --depth 1 origin master
[app-stag01] run: git rev-list --max-count=1 --abbrev-commit --abbrev=12 master
[app-stag01] run: git archive master | tar -x -f - -C /home/deploy/www/git-example/releases/160328-163937/
[app-stag01] run: echo 7fd1a60b01f9 >> REVISION
===> Updated
===> Publishing
[app-stag01] run: ln -nfs /home/deploy/www/git-example/releases/160328-163937 /home/deploy/www/git-example/current
===> Published
===> Finishing
[app-stag01] run: ls -x /home/deploy/www/git-example/releases
===> Finished
Now we have added a repo directory and updated out release directory:
% ssh deploy@lws-stag01 tree /home/deploy/www/git-example
/home/deploy/www/git-example
├── current -> /home/deploy/www/git-example/releases/160328-163937
├── releases
│ └── 160328-163937
│ ├── README
│ └── REVISION
├── repo
│ ├── branches
│ ├── config
│ ├── description
│ ├── FETCH_HEAD
│ ├── HEAD
│ ├── hooks
│ │ ├── applypatch-msg.sample
│ │ ├── commit-msg.sample
│ │ ├── post-update.sample
│ │ ├── pre-applypatch.sample
│ │ ├── pre-commit.sample
│ │ ├── prepare-commit-msg.sample
│ │ ├── pre-push.sample
│ │ ├── pre-rebase.sample
│ │ └── update.sample
│ ├── info
│ │ └── exclude
│ ├── objects
│ │ ├── info
│ │ └── pack
│ │ ├── pack-c8b9cbbd14e791b8beddf1033f5b4357d4f179da.idx
│ │ └── pack-c8b9cbbd14e791b8beddf1033f5b4357d4f179da.pack
│ ├── packed-refs
│ ├── refs
│ │ ├── heads
│ │ └── tags
│ └── shallow
└── shared
└── log
Using Supervisor¶
A static git repository updating is trivial. Let’s get a little bit more complicated now.
We are going to define deploy.yml for a flask hello-world application:
project_name: supervisor-example
app_name: supervisor-example
user: deploy
use_ssh_config: true
stage_role_configs:
staging:
app:
hosts:
- app-stag01
plugins:
- fapistrano.plugins.git
- fapistrano.plugins.virtualenv
- fapistrano.plugins.supervisorctl
repo: git@github.com:liwushuo/fapistrano.git
git_archive_tree: examples/supervisor-example
supervisor_check_status: true
supervisor_conf: configs/supervisor_%(stage)s_%(role)s.conf
Then we add configs/supervisor_staging_app.conf to the repository:
[program:supervisor-example]
command=python app.py
directory=/home/deploy/www/%(program_name)s/current
environment=PATH="/home/deploy/www/%(program_name)s/current/venv/bin",FLASK_ENV="stag"
numprocs=1
user=deploy
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/supervisor/%(program_name)s-web.log
stdout_logfile_maxbytes=100MB
stdout_logfile_backups=10
Finally, Run with option –supervisor-refresh=true, since we first registered our supervisor config to supervisord. In the next release, there is no need to add option –supervisor-refresh=true unless supervisor config file modified.:
[app-stag01] Executing task 'release'
===> Starting
[app-stag01] run: mkdir -p /home/deploy/www/supervisor-example/{releases,shared/log}
[app-stag01] run: chmod -R g+w /home/deploy/www/supervisor-example/shared
[app-stag01] run: mkdir -p /home/deploy/www/supervisor-example/releases/160328-173812
===> Started
[app-stag01] run: git clone --mirror --depth 1 --no-single-branch git@github.com:liwushuo/fapistrano.git /home/deploy/www/supervisor-example/repo
[app-stag01] run: git ls-remote --heads git@github.com:liwushuo/fapistrano.git
[app-stag01] run: ln -nfs /home/deploy/www/supervisor-example/current/configs/supervisor_staging_app.conf /etc/supervisor/conf.d/supervisor-example.conf
===> Updating
[app-stag01] run: git fetch --depth 1 origin master
[app-stag01] run: git rev-list --max-count=1 --abbrev-commit --abbrev=12 master
[app-stag01] run: git archive master examples/supervisor-example | tar -x --strip-components 2 -f - -C /home/deploy/www/supervisor-example/releases/160328-173812/
[app-stag01] run: echo 86ba572f3d8e >> REVISION
===> Updated
[app-stag01] run: /usr/bin/env virtualenv /home/deploy/www/supervisor-example/releases/160328-173812/venv
[app-stag01] run: pip install -U pip setuptools wheel
[app-stag01] run: pip install -r /home/deploy/www/supervisor-example/releases/160328-173812/requirements.txt
===> Publishing
[app-stag01] run: ln -nfs /home/deploy/www/supervisor-example/releases/160328-173812 /home/deploy/www/supervisor-example/current
===> Published
[app-stag01] run: supervisorctl stop supervisor-example
[app-stag01] run: supervisorctl reread
[app-stag01] run: supervisorctl update
[app-stag01] run: supervisorctl start supervisor-example
[app-stag01] run: supervisorctl status supervisor-example
[app-stag01] out: supervisor-example RUNNING pid 13014, uptime 0:00:02
[app-stag01] out:
===> Finishing
[app-stag01] run: ls -x /home/deploy/www/supervisor-example/releases
[app-stag01] run: rm -rf 160328-173248
===> Finished
Now, our flask application is running!:
$ ssh deploy@app-stag01 curl -s http://0.0.0.0:5000
hello world
Rollback!¶
Rollback is easily by replacing release to rollback.
After releasing again, our release are now at 160328-175016.
let’s trigger a rollback flow.:
$ fap rollback --stage staging --role app
staging app
[app-stag01] Executing task 'rollback'
===> Starting
[app-stag01] run: readlink /home/deploy/www/supervisor-example/current
[app-stag01] run: ls -x /home/deploy/www/supervisor-example/releases
===> Started
[app-stag01] run: git ls-remote --heads git@github.com:liwushuo/fapistrano.git
[app-stag01] run: ln -nfs /home/deploy/www/supervisor-example/current/configs/supervisor_staging_app.conf /etc/supervisor/conf.d/supervisor-example.conf
===> Reverting
===> Reverted
===> Publishing
[app-stag01] run: ln -nfs /home/deploy/www/supervisor-example/releases/160328-173812 /home/deploy/www/supervisor-example/current
===> Published
[app-stag01] run: supervisorctl restart supervisor-example
[app-stag01] run: supervisorctl status supervisor-example
[app-stag01] out: supervisor-example RUNNING pid 15272, uptime 0:00:02
[app-stag01] out:
===> Finishing rollback
[app-stag01] run: rm -rf /home/deploy/www/supervisor-example/releases/160328-175016
===> Finished
This command help us rollback our current release back to 160328-173812, which is deployed in last example.
Using with Beeper¶
Beeper is a tool bundling virtualenv.py, wheels and our project as a tar file. With the help of Jenkins, we can build a beeper tgz file before release.
We can use a curl plugin to update our application:
project_name: curl-example
app_name: curl-example
user: deploy
use_ssh_config: true
stage_role_configs:
staging:
app:
hosts:
- app-stag01
plugins:
- fapistrano.plugins.curl
- fapistrano.plugins.supervisorctl
curl_extract_tar: true
curl_postinstall_script: "sh ./install.sh"
supervisor_check_status: true
When running fap release, we can attach option –curl-url. Assuming you are using Jenkins to build your application and have authority to fetch artifact:
$ fap release -s staging -r app --curl-url=http://ci.your-corp.com/view/Server/job/server.builder.curl-example/lastSuccessfulBuild/artifact/dist/curl-example-0f2da63.tar --curl-options="--user $JENKINS_USERNAME:$JENKINS_TOKEN"
Using with Jar¶
If there is a Java application to deploy, it’s recommend to build it to a Jar file. You can integrate fapistrano.plugins.curl to deploy jar.:
project_name: jar-example
app_name: jar-example
user: deploy
use_ssh_config: true
stage_role_configs:
staging:
app:
hosts:
- app-stag01
plugins:
- fapistrano.plugins.localshared
- fapistrano.plugins.curl
- fapistrano.plugins.supervisorctl
# supervisor conf
supervisor_refresh: false
supervisor_output: false
supervisor_check_status: true
# curl conf
curl_output: 'bayarea.jar'