Una de las medidas más importantes que debemos tomar a la hora de realizar proyectos de programación, sobre todo en equipo, es asegurarte de que todos tienen el mismo entorno de trabajo. Si nos referimos a un entorno de aplicaciones en PHP, todos los miembros involucrados deberán tener la misma versión de PHP, las mismas extensiones y la misma configuración del sistema. Además, esas mismas configuraciones deberían ser las mismas en los entornos de test y producción, aunque en producción quitemos las herramientas de debug o depuración. Así, cuando hay un problema, podemos evitar en la medida de lo posible el famoso: «En mi ordenador funciona» cuando al subir cambios al servidor, o al probarlos un compañero, no funcionan.
Tenemos varias opciones al respecto. Podemos utilizar máquinas virtuales con soluciones como Vagrant. Otra opción es utilizar Docker para ejecutar PHP. Incluso podemos ejecutar PHP desde nuestra terminal a través de docker con aplicaciones como composer, o artisan de Laravel.
Tabla de contenidos
Dockerfile
Vamos a basarnos en las imágenes oficiales de php, en este caso php7.2. Y vamos a instalar por defecto extensiones como xml, zip, curl, gettext o mcrypt (esta última debemos instalarla desde pecl.
En los contenedores vamos a vincular /var/www con un directorio local, que puede estar por ejemplo, en la $HOME del usuario actual, donde podremos tener nuestros desarrollos. Y, por otro lado, la configuración de PHP también la vincularemos con un directorio fuera del contenedor, por si tenemos que hacer cambios en algún momento. En teoría no deberíamos permitir esto, la configuración debería ser siempre fija… pero ya nos conocemos y siempre surge algo, lo mismo tenemos que elevar la memoria en algún momento, cambiar alguna directiva o alguna configuración extra.
Dockerfile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | FROM php:7.2-fpm ARG HOSTUID ENV BUILD_DEPS="autoconf file gcc g++ libc-dev make pkg-config re2c libfreetype6-dev libjpeg62-turbo-dev libmcrypt-dev libpng-dev libssl-dev libc-client-dev libkrb5-dev zlib1g-dev libicu-dev libldap-dev libxml2-dev libxslt-dev libcurl4-openssl-dev libpq-dev libsqlite3-dev" \ ETC_DIR="/usr/local/etc" \ ETC_BACKUP_DIR="/usr/local/etc_backup" RUN apt-get update && apt-get install -y less \ procps \ git \ && pecl install redis \ && pecl install xdebug \ && docker-php-ext-enable redis xdebug \ && apt-get install -y $BUILD_DEPS \ && docker-php-ext-install -j$(nproc) iconv \ && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \ && docker-php-ext-install -j$(nproc) gd \ && docker-php-ext-configure imap --with-kerberos --with-imap-ssl \ && docker-php-ext-install -j$(nproc) imap \ && docker-php-ext-install -j$(nproc) bcmath \ && docker-php-ext-install -j$(nproc) calendar \ && docker-php-ext-install -j$(nproc) exif \ && docker-php-ext-install -j$(nproc) fileinfo \ && docker-php-ext-install -j$(nproc) ftp \ && docker-php-ext-install -j$(nproc) gettext \ && docker-php-ext-install -j$(nproc) hash \ && docker-php-ext-install -j$(nproc) intl \ && docker-php-ext-install -j$(nproc) json \ && docker-php-ext-install -j$(nproc) ldap \ && docker-php-ext-install -j$(nproc) sysvshm \ && docker-php-ext-install -j$(nproc) sysvsem \ && docker-php-ext-install -j$(nproc) xml \ && docker-php-ext-install -j$(nproc) zip \ && docker-php-ext-install -j$(nproc) xsl \ && docker-php-ext-install -j$(nproc) phar \ && docker-php-ext-install -j$(nproc) ctype \ && docker-php-ext-install -j$(nproc) curl \ && docker-php-ext-install -j$(nproc) dom \ && docker-php-ext-install -j$(nproc) soap \ && docker-php-ext-install -j$(nproc) mbstring \ && docker-php-ext-install -j$(nproc) posix \ && docker-php-ext-install -j$(nproc) pdo_pgsql \ && docker-php-ext-install -j$(nproc) pdo_sqlite \ && docker-php-ext-install -j$(nproc) pdo_mysql \ && yes | pecl install "channel://pecl.php.net/mcrypt-1.0.1" \ && { \ echo 'extension=mcrypt.so'; \ } > $PHP_INI_DIR/conf.d/pecl-mcrypt.ini \ && echo "Fin de instalaciones" COPY docker-entry.sh /usr/local/binx RUN mv $ETC_DIR $ETC_BACKUP_DIR \ && chmod +x /usr/local/bin/docker-entry.sh \ && rm /etc/localtime RUN useradd -s /bin/bash -d /var/www -u $HOSTUID user ENTRYPOINT ["/usr/local/bin/docker-entry.sh"] CMD ["php-fpm"] |
También tendremos un archivo docker-entry.sh:
1 2 3 4 5 6 7 8 9 10 11 12 13 | #!/bin/bash echo "Iniciando contenedor" VERSION="7.2" CONFFILE=/etc/php/$VERSION/fpm/php-fpm.conf DOCKERIP=$(hostname --ip-address) if [ $(ls $ETC_DIR | wc -l) -eq 0 ]; then echo "Copiando configuración por defecto" cp -r "$ETC_BACKUP_DIR"/* "$ETC_DIR" fi /usr/local/bin/docker-php-entrypoint $@ |
Para construir la máquina podemos utilizar esto:
Utilizo cpuset-cpus para delimitar los núcleos que vamos a utilizar para compilar los módulos. Esto puede tardar un poco y, si tenemos varios núcleos, puede interesarnos utilizar uno o dos, y mientras se construye PHP, utilizar el ordenador para navegar por Internet o algo así. Yo suelo crear un archivo build.sh con esa misma línea de antes.
Ahora, tendremos unos argumentos a la hora de lanzar el contenedor (run.sh)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #!/bin/bash readonly SCRIPTPATH="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" readonly WWWPATH="$HOME/www" GATEWAY="" if [ -n "$(which dnsmasq)" ]; then if [ -z "$(pidof dnsmasq)" ]; then sudo dnsmasq --bind-interfaces fi GATEWAY="--dns $(ip addr show docker0 | grep -Po 'inet \K[\d.]+')" fi pushd $SCRIPTPATH > /dev/null docker run --rm --name myphp7.2-fpm -v /etc/localtime:/etc/localtime:ro -v $WWWPATH:/var/www:rw -v $(pwd)/conf:/usr/local/etc/:rw $GATEWAY --user www-data --cpuset-cpus="7" -d myphp7.2-fpm |
Este archivo podremos reescribirlo dependiendo de nuestra configuración local. En mi ordenador, utilizo dnsmasq como dns en la máquina host, de forma que si modifico mi /etc/hosts, pueda acceder a dichos nombres desde mi contenedor PHP. Además, es conveniente editar en este archivo la variable WWWPATH donde estableceremos la ruta base desde la que tendremos todos nuestros archivos PHP, a partir de la que serviremos con FPM los archivos.
Configurando un servidor web
Este PHP con FPM debemos configurarlo en un servidor web, para ello utilizaremos proxy_fcgi dejando el VirtualHost más o menos así (no he puesto configuración de SSL porque estoy en local, aunque también podríamos configurarla):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <VirtualHost *:80> ServerName prueba_de_mi_web.local ServerAdmin webmaster@localhost Define webpath /prueba_de_mi_web.com DocumentRoot /home/gaspy/www/${webpath} <Directory /home/gaspy/www/${webpath}/> Options +FollowSymLinks AllowOverride all </Directory> <IfModule proxy_fcgi_module> ProxyPassMatch "^/(.*\.ph(p[3457]?|t|tml))$" "fcgi://myphp7.2-fpm.docker.local:9000/var/www/${webpath}/$1" DirectoryIndex index.html index.php </IfModule> ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost> |
Mi $HOME, en mi ordenador es /home/gaspy/ y en www almaceno todo el código de aplicaciones web. En mi /etc/hosts he hecho una entrada que apunta a la IP del contenedor. Para ello puedo utilizar este script que actualiza /etc/hosts con los dockers que hay en ejecución en este momento.
Ejecución desde línea de comandos
Una operación que realizo casi a diario en PHP es la ejecución de scripts desde la línea de comandos. Ya sea por una operación que se realiza en segundo plano, o ejecutar composer, o comandos propios de frameworks o plataformas como artisan de Laravel, occ de Owncloud, yii de su framework homónimo, etc.
Pero claro, para ejecutar los scripts, tengo que hacerlo desde dentro del contenedor, muchas veces con el usuario local y no como root, y generalmente los archivos a ejecutar se encontrarán en mi directorio local, pero dentro del contenedor estarán en /var/www. Además, tenemos que tener en cuenta que muchas veces ejecutaré código php de forma interactiva, es decir, ejecutando php y escribiendo el código, y otras veces haré algo así:
1 2 | <?php echo "Hola mundo!"; |
Para ello, tengo un script que ejecutará php (php7.sh):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #!/bin/bash readonly SCRIPTPATH="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" CURRENT_DIR="$(pwd)/" BASE_DIR="$HOME/www/" DOCKER_DIR="/var/www/" CONTAINER_NAME="myphp7.2-fpm" TRANSLATED_DIR="${CURRENT_DIR/$BASE_DIR/$DOCKER_DIR}" if [ -z "$(docker ps | grep $CONTAINER_NAME)" ]; then $SCRIPTPATH/run.sh fi if [ "$1" == "-u" ]; then shift NUID=$(id -u "$1") shift elif [ "$1" == "-l" ]; then shift NUID=$UID fi if [ -n "$1" ]; then set -- "${1/$BASE_DIR/$DOCKER_DIR}" "${@:2}" QUOTED_ARGS="$(printf " %q" "$@")" fi if [ -n "$NUID" ]; then USER="$(getent passwd 1000 | cut -f1 -d:)" DIR="${DOCKER_DIR}${USER}" if [ ! -d "${BASE_DIR}$USER" ]; then docker exec -u root -i myphp7.2-fpm bash -c "mkdir "$DIR"; chown $NUID:$NUID "$DIR"" fi docker exec -u "$NUID:$NUID" -i myphp7.2-fpm bash -c "HOME="$DIR"; cd $TRANSLATED_DIR 2>/dev/null; exec php ${QUOTED_ARGS}" else docker exec -i myphp7.2-fpm bash -c "cd $TRANSLATED_DIR 2>/dev/null; exec php ${QUOTED_ARGS}" fi |
A este archivo, le podemos crear un enlace dentro de /usr/local/bin/ llamado php para que podamos ejecutarlo desde cualquier sitio:
El script, lo que hace primero es averiguar el directorio actual desde donde ejecutas el script, y transformará dentro de esa cadena la ruta $BASE_DIR (donde están los archivos php en mi ordenador) por la ruta $DOCKER_DIR (donde están los archivos php en el contenedor). De esta forma si, fuera de docker ejecutamos:
Dicho archivo se buscará en el directorio correspondiente dentro del contenedor. Eso sí, fuera de $BASE_DIR no podremos ejecutar archivos. Adicionalmente podremos ejecutar:
Para ejecutar el archivo.php como el usuario www-data o también
Si queremos ejecutar el archivo php como el usuario actual. Además, este script se encarga de lanzar la máquina docker (con run.sh) si no está en ejecución actualmente.
composer y otros scripts parecidos
Composer utilizará el script anterior de php para ejecutarse. Aunque podemos tener un problema con la salida en color. Así que podemos imponerla. Por otro lado, queremos ejecutar composer como el usuario actual, en lugar del usuario www-data, ya que todo lo que instala será código y el código no debe poder ser sobreescrito por ese usuario (generalmente).
Así que podemos crear este script en /usr/local/composer:
1 2 | #!/bin/bash php -u "$(whoami)" /home/gaspy/www/composer --ansi $@ |
Algunas posibilidades
Siempre podemos meter la pata en la configuración, por un lado, si queremos recargar la configuración, tendremos que parar el contenedor y reiniciarlo:
Como vemos, simplemente cargando php se iniciará el contenedor de nuevo. Además, si hemos metido la pata en la configuración, podemos eliminar los archivos del directorio conf y reiniciar el contenedor para que automáticamente se restaure la configuración por defecto.
También podemos incluir nuestra propia configuración en el Dockerfile para que todo nuestro equipo tenga los mismos archivos de configuración la primera vez nada más construir la máquina.
Foto principal: unsplash-logoLuca Bravo
Que GEnIOOOO»!! .. Ty me ayudaste un toquee, me recordaste como solucionar un problema, que tenia.
https://www.tecasoft.com/
y tambien Diseño Web
Muchas Gracias!!!
Vaya por delante que soy un novato en Docker, así que lamento si la pregunta es a lo mejor absurda.
El caso es que me he bajado una imagen que contiene wordpress con letsencrypt, pero la versión de php que utiliza es la 5.6 y necesito actualizarla a la 7.2.
¿Hay alguna forma de modificar esto desde dentro o desde fuera del contenedor?
Gracias de antemano.
Un saludo.
It was fortunate and fortunate that I came to this site and read a lot of interesting information. It is really useful to read. I like so much. Thanks for sharing this great information.
Gracias, quisiera hacerlo con una verion de php la 5.4 o 5.6 pero me da errores, me podrias ayudar?, gracias.
The attention to detail in this jacket is astounding, from the intricate design elements to the high-quality wool fabric. It’s a true work of art that captures the essence of Wakanda and the spirit of T’Challa. Wearing this jacket is not just a fashion statement; it’s a declaration of pride and solidarity
I am overjoyed to come across articles of this nature. Fantastic blog. In addition to taking part in the consolidated meeting minutes, I assure you that I will attend the meeting itself. It has come to my attention that you have, in point of fact, been confronted with a number of extremely practical challenges, and please rest assured that I will continue to review your blog.
Smile Dating Test | At simpleloveagency, we go beyond the ordinary to offer you an exceptional dating experience that revolves around your safety, comfort, and privacy. Our platform isn’t just about connecting people – it’s about creating meaningful connections that can potentially lead to lasting relationships. Here are the remarkable benefits you can enjoy:
Gracias por compartir este artículo tan detallado.
This piece of writing stands out like a breath of fresh air within its domain. It presents an original viewpoint, questions established norms, and fosters a culture of analytical thinking. It’s a must-dive-into for individuals in search of novel perspectives!
gym trainer brisbane
The words we say to ourselves matter. Replacing negative self-talk with positive affirmations can boost your self-esteem and resilience. Rip Wheeler Coat remind yourself daily of your worth and capabilities.
Oh! Another great suggestion you posted. I will post some articles on similar topics on my blog, hoping that you can access and experience the same as me! Thank you for reading your wonderful article.메이저사이트
Thank you so much for your kind words! I’m glad to hear that you find the blog informative Siebel crm remote job support
The best faux leather jackets are the ones that actually make you happy. And our effort is to provide you with pleather jacket womens. So visit our site now.
It was a very good post indeed. I thoroughly enjoyed reading it in my lunch time. Will surely come and visit this blog more often. Thanks for sharing. Visit us for getting best online tuition bahrain. Thank You!
This is a very cool article, and I enjoy reading it. Your blog is great, and you have good employees in it. Nice sharing, keep going. 메이저사이트
Love this blog! Thanks for this! Website design
Watch free anime with English subtitles
Animension.ch is a popular anime streaming website that offers a vast library of anime content for fans worldwide. It is essential because it allows fans to watch their favourite anime shows and movies online for free.
«Such a well-researched and informative piece.
https://accountantsedmonton.net«
Good comment! Nice to meet you. I live in different countries with you. But the greed for exploring the painful realm of ‘you’ seems to be the same! I always come back when there are new articles published.메이저사이트
I like the helpful information you provide in your articles. I will bookmark your website and check again here regularly.
pool builder bradenton
this blog was really great, never seen a great blog like this before. i think im gonna share this to my friends..
it exceeded my expectations! It’s not only delicious but also really convenient for my busy schedule. Plus, switzerland-carservice
love how you break down complex topics into easily digestible information. Looking forward to reading more from you!» realtormyranda
Day or night, chat with them online and they will try to answer all your queries online psychology assignment help
Xender is a record moving and sharing application for Android gadgets. This information move application permits clients to handily move and offer records quicker without relying upon the web or Bluetooth availability.
Harley Quinn Jacket The iconic Harley Quinn character is a dark-faced, mischievous, flamboyant, and curvy character. She loves to cause mischief and is not afraid to get her hands dirty when it comes to causing chaos. She is a master at using her femininity to her advantage and is often used as a source of laughs and punchlines by the Joker.
Purchase the best quality CBD Flowers and CBD oils in Switzerland.
I enjoyed reading your blog post. The topic is interesting, and you presented it in a clear and engaging manner. Metal Stairs Boston
Our Dubai Desert Safari are perfectly suitable for Sole, Other than visiting malls, dine in restaurants or city sightseeing, for an adventure break
I will review more high-quality online content again and recommend this website to everyone. Thank you.메이저사이트
Join elite, cost-free Telegram groups for crypto signals in 2023. Trading Signals Telegram
Telegram Crypto Groups
The blog section on this site is fantastic! The content is engaging, and I always look forward to reading the latest posts. Highly recommended! Pressure Washing Services Fayetteville
When programming with PHP, you must be aware of error messages. These can be errors, notices and warnings. Errors are fatal run-time errors that will cause PHP to stop executing your script. Notices and warnings are non-fatal errors.
One way to learn PHP is by reading a book. This can be done online or at your local library.