Jak se ^bonami\.(cz|pl|sk)$ vešlo
do kontejneru Václav Boch, Bonami.cz
31.3.2016
What you can use for deployment?
• FTP
• SFTP/SSHFS
• GIT
• Bash
• Capistrano
• RPM
• Docker
Docker
• Docker is shipping container for your application.
• Contains everything that your app needs.
Virtualization vs. Docker
AppA
Hypervisor
Host OS
Server
GuestOS
Bins/Libs
VM
AppC
GuestOS
Bins/Libs
AppB
GuestOS
Bins/Libs
Ap
p A
’
Do
cker
Host OS
Server
Bins/Libs
Ap
p A
Bins/LibsA
pp
B
Ap
p B
’
Ap
p B
’
Ap
p B
’Container
Image
• Layers
• Read Only
• Running image is container
Base Image (Ubuntu / Alpine)
Apps PHP, extensions, vim,runtime configuration
Your configuration + ceritificates
Your codeRead only
Cache warm up
Container
• Running image
• The last layer of image
• Only layer that is writable
Base Image (Ubuntu / Alpine)
Apps PHP, extensions, vim,runtime configuration
Your configuration + ceritificates
Your code
Running container (tmp files)
Read only
Writable
Cache warm up
Production & test Image
Base Image (Ubuntu / Alpine)
Apps PHP, extensions, vim,runtime configuration
Your prod configuration + ceritificates
Your code
Bonami Base
Cache warm up
Your test configuration + ceritificates
Test tools (PHPUnit)
Cache warm up
Production image
Test image
Source Coderepo
DockerRegistry
How does it work?
DockerfileFor
Core, Test, Prod
Docker Engine
Push
Do
cker
Production server + Docker
Push
SearchPullRun
Host CI server
Co
ntain
erA
Co
ntain
erB
Co
ntain
erC
Base Im
age
Local DEV machine CI server Production
Test Image
Prod Image
Search
Pull & Run
Do
cker
Test server + DockerC
on
tainerA
Co
ntain
erB
Co
ntain
erC
Build
Bonami Base – Dockerfile
FROM registry.bonami.cz/bonami/fedoraENV TERM xtermRUN dnf install -y \
php-fpm php-cli php-curl php-intl php-mysql php-mcrypt php-gd php-redis php-igbinary \php-pecl-http php-pecl-imagick php-bcmath vim sudo php-mbstring php-xml php-soap php-pdo \php-mysqlnd php-opcache php-twig redis php-pecl-apcu msmtp nginx tar && \
curl -SLO "https://nodejs.org/dist/v0.12.7/node-v0.12.7-linux-x64.tar.gz" && \tar -xzf "node-v0.12.7-linux-x64.tar.gz" -C /usr/local --strip-components=1 && \rm -f /node-v0.12.7-linux-x64.tar.gz && \mkdir -p /var/www/bonami-web && \echo "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" >> /etc/environment && \dnf clean all && \rm -rf /var/cache/dnf && \rm -rf /var/log/dnf && \
sed -i -e "s/\([;]*\)\(upload_max_filesize[ \t]*=\)\(.*\)$/\2 16M /g" /etc/php.ini && \sed -i -e "s/\([;]*\)\(date.timezone[ \t]*=\)\(.*\)$/\2 \"Europe\/Prague\" /g" /etc/php.ini
Bonami Dockerfile
FROM registry.bonami.cz/bonami/bonami-runtime
COPY . /var/www/bonami-web
RUN chown -R apache:apache /var/www/bonami-web/app/cache /var/www/bonami-web/app/logs && \chmod 775 /var/www/bonami-web/app/cache /var/www/bonami-web/app/logs && \cp /var/www/bonami-web/docker/nginx_staticfiles.conf /etc/nginx/nginx.conf && \sudo -u apache /var/www/bonami-web/app/console cache:warmup --env=prod
ENTRYPOINT ["/var/www/bonami-web/docker/start.sh"]
#!/bin/bash
case "$1" in
fpm)
echo "PHP-FPM starting on port 9000..."
exec ${fpmBinary} -F
;;
cron)
if [ ! -f $DIR/tools/docker/crontab/$2 ]; then
echo "error: specified crontab does not exist in crontab directory" >&2; exit 1
fi
echo "Crontab $2 starting..."
exec sudo -u $wwwUser ${cronBinary} $DIR/tools/docker/crontab/$2
;;
daemon|job|script|tool)
if [ -z $2 ] || [ ! -x $DIR/bin/$1s/$2 ]; then
echo "error: $1 does not exist" >&2; exit 1
fi
arr=(sudo -u $wwwUser BONAMI_ENVIRONMENT=prod $DIR/bin/$1s/$2)
exec "${arr[@]}"
;;
bash)
exec /bin/bash
;;
static)
echo "Static content is served on port 8080..."
exec /usr/sbin/nginx -g "daemon off;"
;;
echo $"Usage: {fpm|daemon|job|cron|bash|script|static|tool|git_hash}"
exit 2
esac
Entrypoint
Some guidelines
• Only one application in container (no Supervisord)
• There is no need for SSHd (we have Docker exec)
• Keep the container small (remove all that is not necessary)
• Keep layers count small
• If you use some tmp files, delete them in same layer
How to deploy our image?
[email protected]~$ sudo docker run -d --log-opt "gelf-address=udp://quimby.bonami.cz:12201" --name "bonamiweb-fpm" --log-driver "gelf" --volume "/tmp:/tmp" --net "host" --restart "always" registry.bonami.cz/bonami/bonamiweb:latest daemon flexibee-queue-daemon
Fabric
• SSH Connection manager + some usefull tools
• Written in Python
• http://www.fabfile.org/
from fabric.api import *
from fabric.colors import *
from fabric.operations import prompt
env.forward_agent = True
env.use_ssh_config = True
env.user = "deploy"
env.deployServer = "quimby.bonami.cz"
@hosts(env.deployServer)
def deploy(service):
_load_service_configuration(service)
execute (_run_hooks, "onLoad", hosts=env.config["hooks"].keys());
_set_current_release()
_wait_for_jenkins()
_check_build_status()
execute(_run_hooks, "onStart", hosts=env.config["hooks"].keys());
execute(_docker_login, hosts = env.config["hosts"].keys());
execute(_docker_pull, hosts = env.config["hosts"].keys());
execute(_run_hooks, "beforeReplace", hosts = env.config["hooks"].keys());
execute(_docker_replace, hosts = env.config["hosts"].keys());
execute(_run_hooks, "afterReplace", hosts = env.config["hooks"].keys());
Fabric
[email protected]~$ cat config/bonamiweb.ymljenkins:
username: fabricpassword: supertajneheslohost: "https://jenkins.bonami.cz"job: bonami-production
registry:host: "registry.bonami.cz"username: fabricpassword: supertajneheslo
keepReleases: 5
hooks:homer.bonami.cz:
beforeReplace:- "echo \"Switching to deploy virtualhost\""- "sudo rm /etc/nginx/sites/bonami.cz.conf"- "sudo ln -s /etc/nginx/sites-available/deploy.bonami.cz.conf /etc/nginx/sites/bonami.cz.conf"- "sudo service nginx reload"
afterReplace:- "echo \"Switching to live virtualhost\""- "sudo rm /etc/nginx/sites/bonami.cz.conf"- "sudo ln -s /etc/nginx/sites-available/bonami.cz.loadbalace.conf /etc/nginx/sites/bonami.cz.conf"- "sudo service nginx reload"- "curl -X POST --data-urlencode 'payload={\"channel\": \"#dev\", \"username\": \"deploy\", \"text\":
\"It'\"'\"'s alive!\", \"icon_emoji\": \":computer:\"}' https://hooks.slack.com/services/..."
Deploy skript
hosts:apu.bonami.cz:- image: bonami/bonamiweb
name: "bonamiweb-draft-storage-daemon"restart: alwaysnet: hostarg: "daemon draft-storage-daemon"volume:
- "/tmp:/tmp:ro"
homer1.bonami.cz:- image: bonami/bonamiweb
name: "bo namiweb-fpm"restart: alwaysnet: hostarg: "fpm 9000"
- image: bonami/redisname: "redis"restart: alwaysnet: host
- image: bonami/bonamiwebname: "bonamiweb-static"restart: alwaysnet: hostarg: "static"
Deploy skript
Vašek Boch
That’s it.
@vasekboch
Do you want to work with us?
https://www.startupjobs.cz/startup/bonami-cz