Run Yii in Docker container locally

In this article I want to tell you what I did to automatically deploy NginX, php-fcgi and install Yii using docker. It can be usefull for local development. Eventually it was written many years ago so some steps might be outdated.

For this container I used Yii 2 Starter Kit

So we have a server or PC with docker installed. I located all files in /opt/docker folder so first lets create it:

mkdir /opt/docker/yii

I will be using two separate containers:

  • yiiweb (nginx+php+yii)
  • yiidb (mysql)

Lets create folders for them:

mkdir /opt/docker/yii/web  
mkdir /opt/docker/yii/db

Switch to the container folder:

cd /opt/docker/yii

To get started we need the following files:

  • backend.conf and frontend.conf - site configs for nginx
  • env - the file that will go to the site folder. It describes the framework settings.
  • php-fastcgi-init - starter script for php
  • php-fastcgi-bin is another script for php to work
  • autoconf.sh - this script needs to be executed in the container after startup.

The next two files are nothing special - nginx configs for two sites. You’ll need to customize them accordingly.

backend.conf
server {
    listen 80;
    server_name backend.yiisite.com admin.yiisite.com;

    root /var/www/html/website/backend/web;

    index index.php;

    # Limit methods, allowed on server to GET, HEAD and POST
    if ($request_method !~ ^(GET|HEAD|POST)$ ) {
return 444;
    }

    location ~* \.(ico|gif|jpeg|jpg|png|eot|ttf|swf|woff)$ {
root /var/www/html/website/backend/web;
expires 30d;
access_log off;
    }

    location ~* \.(css|js)$ {
root /var/www/html/website/backend/web;
expires 7h;
access_log off;
    }

    location / {
try_files $uri $uri/ /index.php;
    }

    location ~ \.(php|html)$ {
root /var/www/html/website/backend/web;

	fastcgi_param PATH_INFO $fastcgi_path_info;
	fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
	fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
	fastcgi_split_path_info ^(.+\.php)(/.+)$;

fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
    }
}
frontend.conf
server {
    listen 80;
    server_name yiisite.com;

    root /var/www/html/website/frontend/web;

    index index.php;

    # Limit methods, allowed on server to GET, HEAD and POST
    if ($request_method !~ ^(GET|HEAD|POST)$ ) {
return 444;
    }

    location ~* \.(ico|gif|jpeg|jpg|png|eot|ttf|swf|woff)$ {
root /var/www/html/website/frontend/web;
expires 30d;
access_log off;
    }

    location ~* \.(css|js)$ {
root /var/www/html/website/frontend/web;
expires 7h;
access_log off;
    }

    location / {
try_files $uri $uri/ /index.php;
    }

    location ~ \.(php|html)$ {
root /var/www/html/website/frontend/web;

	fastcgi_param PATH_INFO $fastcgi_path_info;
	fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
	fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
	fastcgi_split_path_info ^(.+\.php)(/.+)$;

fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
    }
}

In the following spoiler please pay attention to the database, username and password in bold. They will be generated when the database instance is built. The yiiweb instance will use the hostname yiidb to communicate with the mysql instance:

env
# Framework
# ---------
YII_DEBUG   = false
YII_ENV     = prod

# Databases
# ---------
DB_DSN     = mysql:host=yiidb;port=3306;dbname=yiidb
DB_USERNAME= yiiuser
DB_PASSWORD= yiipasswd
DB_TABLE_PREFIX  =

# Urls
# ----
FRONTEND_URL    = http://yiisite.com
BACKEND_URL     = http://backend.yiisite.com
STORAGE_URL     = http://storage.yiisite.com

# Other
# -----
FRONTEND_COOKIE_VALIDATION_KEY = 7VDYlzcbOcxPJNh8Z2ZNDoRXauT2p1_T
BACKEND_COOKIE_VALIDATION_KEY = JbbAiWyG5isNQSz4FoIblVSxg0mdpOUF
ADMIN_EMAIL = [email protected]
ROBOT_EMAIL = [email protected]
GITHUB_CLIENT_ID = your-client-id
GITHUB_CLIENT_SECRET = your-client-secret

Based on an article about configuring nginx+php-fcgi we create the following files. During the container build they will be located in the correct paths:

php-fastcgi-init
#!/bin/sh
#
# php-fastcgi - Use PHP as a FastCGI process via nginx.
#
# chkconfig: - 85 15 description: Use PHP as a FastCGI process via nginx. processname: php-fastcgi pidfile: /var/run/php-fastcgi.pid Source function library.
. /etc/rc.d/init.d/functions
# Source networking configuration.
. /etc/sysconfig/network
# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0

phpfastcgi="/usr/bin/php-fastcgi"
prog=$(basename php-cgi)
lockfile=/var/lock/subsys/php-fastcgi

start() {
    [ -x $phpfastcgi ] || exit 5
    echo -n $"Starting $prog: "
    daemon $phpfastcgi
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}
stop() {
    echo -n $"Stopping $prog: "
    killproc $prog -Q
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}
restart() {
    configtest || return $?
    stop
    start
}
reload() {
    configtest || return $?
    echo -n $"Reloading $prog: "
    killproc $prog -HUP
    RETVAL=$?
    echo
}
force_reload() {
    restart
}
rh_status() {
    status $prog
}
rh_status_q() {
    rh_status >gt;/dev/null 2>gt;&1
}
case "$1" in
    start)
rh_status_q && exit 0
$1
;;
    stop)
rh_status_q || exit 0
$1
;;
    restart|configtest)
$1
;;
    reload)
rh_status_q || exit 7
$1
;;
    force-reload)
force_reload
;;
    status)
rh_status
;;
    condrestart|try-restart)
rh_status_q || exit 0
;;
    *)
echo $"Usage: $0 {start|stop|status|restart}"
exit 2
esac
php-fastcgi-bin
#!/bin/bash

FASTCGI_USER=nginx
FASTCGI_GROUP=nginx
ADDRESS=127.0.0.1
PORT=9000
PIDFILE=/var/run/php-fastcgi.pid
CHILDREN=6
PHP5=/usr/bin/php-cgi

/usr/bin/spawn-fcgi -a $ADDRESS -p $PORT -P $PIDFILE -C $CHILDREN -u $FASTCGI_USER -g $FASTCGI_GROUP -f $PHP5

The whole beauty of automatic configuration lies in the following script. You need an account on github.com to use it. If you don’t have one than go ahead and register. Next edit the script (\r should remain at the end).

This script cannot be executed at the stage of container initialization (the so-called build) since at this stage docker does not link containers and does not mount partitions.

autoconf.sh
#!/bin/bash
git clone https://github.com/trntv/yii2-starter-kit.git /var/www/html/website

cd /var/www/html/website

expect -c 'set timeout 3600; spawn composer install; expect "Username:" {send -- "[email protected]\r";}; expect "Password:" { send -- "password\r"}; interact'

expect -c 'set timeout 3600; spawn ./init; expect "Your choice " {send -- "1\r"}; expect "Initialize the application" {send -- "yes\r"}; interact'

cp /root/env /var/www/html/website/.env

expect -c 'set timeout 3600; spawn php console/yii migrate; expect "Apply the above migrations" {send -- "yes\r"}; interact'

php console/yii rbac/init

chown -R nginx:nginx /var/www/html

The preparation is finished. Let’s move on

Create Dockerfile:

Dockerfile
FROM centos:6
# install the PHP extensions we need
# Add repos
RUN rpm -Uhv http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
RUN rpm -Uhv http://rpms.famillecollet.com/enterprise/remi-release-6.rpm

# Install stuff using yum from peel and remi repos
RUN yum install spawn-fcgi expect openssh openssh-server git php-common php php-pdo php-gd php-pecl-memcache php-mbstring php-xmlrpc php-devel php-soap php-mysql php-cli php-pear php-snmp php-xml php-intl php-pspell php-pecl-zendopcache nginx -y --enablerepo=epel --enablerepo=remi --enablerepo=remi-php55

# Copy websites' configuration files to nginx folder
COPY backend.conf /etc/nginx/conf.d/
COPY frontend.conf /etc/nginx/conf.d/

# Configure php to run in fastcgi mode
COPY php-fastcgi-init /etc/rc.d/init.d/
RUN mv /etc/rc.d/init.d/php-fastcgi-init /etc/rc.d/init.d/php-fastcgi && chmod +x /etc/rc.d/init.d/php-fastcgi

COPY php-fastcgi-bin /usr/bin/
RUN mv /usr/bin/php-fastcgi-bin /usr/bin/php-fastcgi && chmod +x /usr/bin/php-fastcgi

# Install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/bin
RUN mv /bin/composer.phar /bin/composer
RUN composer global require "fxp/composer-asset-plugin"

# Attach website folder
VOLUME /var/www/html

# Add autoconfigure script to container
COPY env /root/
COPY autoconf.sh /root/

EXPOSE 80

CMD /etc/rc.d/init.d/php-fastcgi start && service nginx start && /bin/sh -c "while true; do sleep 1; done"

Create docker-compose.yml with the following contexts:

docker-compose.yml

yiiweb:
  build: .
  ports:
    - 80:80
  links:
    - yiidb
  volumes:
    - ./web:/var/www/html

yiidb:
  image: mysql
  ports:
    - 3306:3306
  volumes:
    - ./db:/var/lib/mysql
  environment:
    MYSQL_DATABASE: yiidb
    MYSQL_USER: yiiuser
    MYSQL_PASSWORD: yiipasswd
    MYSQL_ROOT_PASSWORD: rootpasswd

Let’s build the container:

docker-compose build

Run the following to launch the container:

docker-compose up -d

Now we need to run the autoconf.sh.

Get the list of contianers running:

docker ps

You’ll get the table that consists on multiple columns and a 2 rows. The first collumn contains the id of the container. The last one contains the name of the container. You can use either container_id or container_name in the following command:

docker exec %container_id% bash /root/autoconf.sh

You can attach to the container console by running the following:

docker exec -ti %container_id% bash

Run the following in the container console:

bash /root/autoconf.sh

Tags:

Categories:

Updated: