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
App
A
Hypervisor
HostOS
Server
Guest
OS
Bins/
Libs
VM
App
C
Guest
OS
Bins/
Libs
App
B
Guest
OS
Bins/
Libs
AppA’
Docker
HostOS
Server
Bins/Libs
AppA
Bins/Libs
AppB
AppB’
AppB’
AppB’
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
Code
repo
Docker
Registry
How does it work?
Dockerfile
For
Core,
Test, Prod
Docker Engine
Push
Docker
Production server + Docker
Push
Search
Pull
Run
HostCI server
ContainerA
ContainerB
ContainerC
BaseImage
Local DEV machine CI server Production
Test Image
Prod Image
Search
Pull & Run
Docker
Test server + Docker
ContainerA
ContainerB
ContainerC
Build
Bonami Base – Dockerfile
FROM registry.bonami.cz/bonami/fedora
ENV TERM xterm
RUN 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?
boch@bart.bonami.cz~$ 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
deploy@quimby.bonami.cz~$ cat config/bonamiweb.yml
jenkins:
username: fabric
password: supertajneheslo
host: "https://jenkins.bonami.cz"
job: bonami-production
registry:
host: "registry.bonami.cz"
username: fabric
password: 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: always
net: host
arg: "daemon draft-storage-daemon"
volume:
- "/tmp:/tmp:ro"
homer1.bonami.cz:
- image: bonami/bonamiweb
name: "bo namiweb-fpm"
restart: always
net: host
arg: "fpm 9000"
- image: bonami/redis
name: "redis"
restart: always
net: host
- image: bonami/bonamiweb
name: "bonamiweb-static"
restart: always
net: host
arg: "static"
Deploy skript
Vašek Boch
That’s it.
@vasekboch
vaclav.boch@bonami.cz
Do you want to work with us?
hledamevyvojare@bonami.cz
https://www.startupjobs.cz/startup/bonami-cz

Jak se ^bonami\.(cz|pl|sk)$ vešlo do kontejneru

  • 1.
    Jak se ^bonami.(cz|pl|sk)$vešlo do kontejneru Václav Boch, Bonami.cz 31.3.2016
  • 2.
    What you canuse for deployment? • FTP • SFTP/SSHFS • GIT • Bash • Capistrano • RPM • Docker
  • 3.
    Docker • Docker isshipping container for your application. • Contains everything that your app needs.
  • 4.
  • 5.
    Image • Layers • ReadOnly • Running image is container Base Image (Ubuntu / Alpine) Apps PHP, extensions, vim, runtime configuration Your configuration + ceritificates Your codeRead only Cache warm up
  • 6.
    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
  • 7.
    Production & testImage 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
  • 8.
    Source Code repo Docker Registry How does itwork? Dockerfile For Core, Test, Prod Docker Engine Push Docker Production server + Docker Push Search Pull Run HostCI server ContainerA ContainerB ContainerC BaseImage Local DEV machine CI server Production Test Image Prod Image Search Pull & Run Docker Test server + Docker ContainerA ContainerB ContainerC Build
  • 9.
    Bonami Base –Dockerfile FROM registry.bonami.cz/bonami/fedora ENV TERM xterm RUN 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
  • 10.
    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"]
  • 11.
    #!/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
  • 12.
    Some guidelines • Onlyone 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
  • 13.
    How to deployour image? boch@bart.bonami.cz~$ 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
  • 14.
    Fabric • SSH Connectionmanager + some usefull tools • Written in Python • http://www.fabfile.org/
  • 15.
    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
  • 16.
    deploy@quimby.bonami.cz~$ cat config/bonamiweb.yml jenkins: username:fabric password: supertajneheslo host: "https://jenkins.bonami.cz" job: bonami-production registry: host: "registry.bonami.cz" username: fabric password: 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
  • 17.
    hosts: apu.bonami.cz: - image: bonami/bonamiweb name:"bonamiweb-draft-storage-daemon" restart: always net: host arg: "daemon draft-storage-daemon" volume: - "/tmp:/tmp:ro" homer1.bonami.cz: - image: bonami/bonamiweb name: "bo namiweb-fpm" restart: always net: host arg: "fpm 9000" - image: bonami/redis name: "redis" restart: always net: host - image: bonami/bonamiweb name: "bonamiweb-static" restart: always net: host arg: "static" Deploy skript
  • 18.
    Vašek Boch That’s it. @vasekboch vaclav.boch@bonami.cz Doyou want to work with us? hledamevyvojare@bonami.cz https://www.startupjobs.cz/startup/bonami-cz