Docker para Symfony 4: de LAN a producción

Prehistoria


Un buen día necesitaba implementar un entorno de desarrollo para mi proyecto. Vagrant ya estaba harto y quería tener un entorno de desarrollo único para todos los participantes del proyecto que fuera idéntico al servidor de producción. En consecuencia, después de escuchar información sobre el acoplador inconformista, decidí comenzar a lidiar con él. A continuación, intentaré describir con el mayor detalle posible todos los pasos desde la instalación de una ventana acoplable en una LAN hasta la implementación de un producto en KVM.

Pila de tecnología original:

docker
- Symfony 4
- nginx
- php-fpm
- postgresql
- búsqueda elástica
- rabbitmq
- jenkins

Hierro:

- computadora portátil con sistema operativo Ubuntu 16.04
- servidor de producción en alojamiento KVM

¿Por qué, además de la pila tecnológica, también enumeré la pila de hierro?

Si nunca antes ha trabajado con una ventana acoplable, puede encontrar una serie de problemas relacionados específicamente con el hardware, el sistema operativo de su computadora portátil o el tipo de virtualización de alojamiento.

El primer y probablemente el aspecto más importante al comenzar a trabajar con la ventana acoplable es el sistema operativo de su computadora portátil. La forma más fácil de trabajar con Docker es en sistemas Linux. Si trabaja en Windows o Mac, tendrá un 100% de dificultades, pero estas dificultades no serán críticas y si desea "googlear" cómo se soluciona esto, no habrá problemas.

La segunda pregunta es el alojamiento. ¿Por qué se necesita Hosting con el tipo de virtualización KVM? La razón es que la virtualización de VPS es muy diferente de KVM y simplemente no podrá instalar docker en VPS, ya que VPS asigna dinámicamente los recursos del servidor.

Subtotal: para el inicio más rápido en la ventana acoplable, es más razonable elegir Ubuntu como SO local y alojamiento KVM (o su propio servidor). Además, la historia dependerá precisamente de estos dos componentes.

Docker-compose para LAN


Instalación


Primero debe instalar la ventana acoplable localmente. Puede ver las instrucciones de instalación en el enlace del sitio web oficial a la documentación oficial de ubuntu (necesita instalar docker y docker-compose), o ejecutando el comando en la consola:

curl -sSl https://get.docker.com/ | sh 

Este comando instalará docker y docker-compose. Después de eso, verifique la versión de Docker con el comando:

 docker --version 

Estoy comenzando todo esto en la versión Docker 18.06.0-ce.

¡La instalación está completa!

Conciencia


Para trabajar con algo con menos éxito, debe tener una idea de cómo funciona. Si anteriormente trabajó solo con Vagrant o algo similar, entonces será extremadamente inusual e incomprensible al principio, pero esto es solo al principio.

Intentaré dibujar una analogía para Vagrant. Ahora muchos pueden decir que comparar Vagrant y Docker es fundamentalmente incorrecto. Sí, estoy de acuerdo con esto, pero no voy a compararlos, solo intentaré transmitirles a los recién llegados que trabajaron solo con el sistema de trabajo Vagrant the Docker, apelando a lo que saben los recién llegados.

Mi visión del contenedor "en los dedos" es la siguiente: cada contenedor es un pequeño mundo aislado. Cada contenedor se puede imaginar como si fuera un pequeño Vagrant en el que solo está instalada 1 herramienta, por ejemplo nginx o php. Inicialmente, los contenedores generalmente están aislados de todo lo que hay a su alrededor, pero mediante manipulaciones difíciles, puede configurar todo para que se comuniquen entre sí y trabajen juntos. Esto no significa que cada uno de los contenedores sea una máquina virtual separada, en absoluto. Pero es más fácil para la comprensión inicial, como me parece.

Vagrant simplemente muerde parte de los recursos de su computadora, crea una máquina virtual, instala un sistema operativo en ella, instala bibliotecas, instala todo lo que escribió en el script después de vagrant. En definitiva, se parece a esto:

Ver esquema

Docker, a su vez, funciona radicalmente diferente. No crea máquinas virtuales. Docker crea contenedores (por ahora, puede pensar en ellos como máquinas micro virtuales) con su sistema operativo Alpine y 1-3 bibliotecas que son necesarias para que la aplicación funcione, por ejemplo php o nginx. Al mismo tiempo, Docker no bloquea los recursos de su sistema por sí mismo, sino que simplemente los usa según sea necesario. En última instancia, para ilustrar, se verá más o menos así:

Ver esquema

Cada uno de los contenedores tiene una imagen a partir de la cual se crea. La gran mayoría de las imágenes es una extensión de otra imagen, por ejemplo, Ubuntu xenial o Alpine o Debian, en la que se colocan controladores adicionales y otros componentes en la parte superior.

Mi primera imagen fue para php-fpm. Mi imagen extiende la imagen oficial de php: 7.2-fpm-alpine3.6. Es decir, en esencia, toma la imagen oficial y entrega los componentes que necesito, por ejemplo, pdo_pgsql, imagick, zip, etc. Por lo tanto, puede crear la imagen que necesita. Si quieres, puedes usarlo aquí .

Con la creación de imágenes, todo es bastante simple en mi opinión si se hacen sobre la base de xenial, por ejemplo, pero entregan un poco de hemorroides si se hacen sobre la base de Alpine. Antes de comenzar a trabajar con la ventana acoplable, básicamente no escuché sobre Alpine, ya que Vagrant siempre trabajó para mí en Ubuntu xenial. Alpine es un sistema operativo Linux vacío, en el que esencialmente no hay nada en absoluto (mínimo extremo). Por lo tanto, al principio es extremadamente inconveniente trabajar con él, ya que existe, por ejemplo, la misma instalación de apt-get (a la que te acostumbras), pero solo hay apk add y un conjunto de paquetes no del todo sensato. Una gran ventaja de Alpine es su peso, por ejemplo, si Xenial pesa (en abstracto) 500 bolsas, entonces Alpine (en abstracto) es de aproximadamente 78 bolsas. ¿Qué afecta esto? Y esto afecta la velocidad de construcción y el peso final de todas las imágenes que se almacenarán en su servidor al final. Digamos que tiene 5 contenedores diferentes y todo basado en xenial su peso total será de más de 2.5 gigas, y alpino, alrededor de 500 bolsas solamente. Por lo tanto, idealmente, debemos esforzarnos por garantizar que los contenedores sean lo más delgados posible. (Enlace útil para instalar paquetes en Alpine - paquetes Alpine ).

En todas partes del Docker Hub escriben cómo iniciar el contenedor utilizando el docker run , y por alguna razón no escriben cómo se puede iniciar a través de Docker-Comose, y es a través de Docker-Comose que comenzará la mayor parte del tiempo, ya que hay muy poca caza Inicie manualmente todos los contenedores, redes, puertos abiertos y más. Docker-compose en nombre del usuario solo parece un archivo yaml con configuraciones. Incluye una descripción de cada uno de los servicios que deben iniciarse. Mi construcción para el entorno local es la siguiente:

 version: '3.1' services: php-fpm: image: otezvikentiy/php7.2-fpm:0.0.11 ports: - '9000:9000' volumes: - ../:/app working_dir: /app container_name: 'php-fpm' nginx: image: nginx:1.15.0 container_name: 'nginx' working_dir: /app ports: - '7777:80' volumes: - ../:/app - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf postgres: image: postgres:9.6 ports: - '5432:5432' container_name: 'postgresql' working_dir: /app restart: always environment: POSTGRES_DB: 'db_name' POSTGRES_USER: 'db_user' POSTGRES_PASSWORD: 'db_pass' volumes: - ./data/dump:/app/dump - ./data/postgresql:/var/lib/postgresql/data rabbitmq: image: rabbitmq:3.7.5-management working_dir: /app hostname: rabbit-mq container_name: 'rabbit-mq' ports: - '15672:15672' - '5672:5672' environment: RABBITMQ_DEFAULT_USER: user RABBITMQ_DEFAULT_PASS: password RABBITMQ_DEFAULT_VHOST: my_vhost elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:6.3.0 container_name: 'elastic-search' environment: - discovery.type=single-node - "discovery.zen.ping.unicast.hosts=elasticsearch" - bootstrap.memory_lock=true - "ES_JAVA_OPTS=-Xms512m -Xmx512m" ports: - 9200:9200 - 9300:9300 working_dir: /app volumes: - ../:/app - ./data/elasticsearch:/usr/share/elasticsearch/data volumes: elasticsearch: postgresql: 

docker-compose.yaml para SF4 es un determinado conjunto de servicios: nginx, php-fpm, postgresql, rabbitmq (si lo necesita), elasticsearch (si lo necesita). Para el medio ambiente local, esto es suficiente. Para que todo funcione, hay una configuración mínima, sin la cual nada funcionará. En la mayoría de los casos, estos son imagen, volúmenes, puertos, entorno, directorio de trabajo y nombre de contenedor. Todo para iniciar esta o aquella imagen se describe en su documentación en hub.docker.com . No siempre hay una descripción para docker-compose, pero esto no significa que no funcione con ella. Solo es necesario transferir todos los datos entrantes del comando docker run a docker-compose y todo funcionará.

Por ejemplo, hay una imagen para RabbitMQ aquí . Cuando ves ESTO por primera vez, causa sentimientos y emociones mezclados, pero no todo es tan aterrador. Las etiquetas se indican en esta imagen. Por lo general, las etiquetas representan diferentes imágenes, diferentes versiones de la aplicación con diferentes imágenes expandibles. Por ejemplo, la etiqueta 3.7.7-alpine significa que esta imagen es más delgada que, por ejemplo, 3.7.7, ya que está basada en Alpine. Bueno, y también en las etiquetas, con mayor frecuencia se indican las versiones de la aplicación. Por lo general, elijo la última versión y la versión estable de la aplicación en sí y la imagen alpina.

Después de haber estudiado y seleccionado una etiqueta, a menudo verá algo de este tipo:

 docker run -d --hostname my-rabbit --name some-rabbit -e RABBITMQ_DEFAULT_USER=user -e RABBITMQ_DEFAULT_PASS=password rabbitmq:3-management 

¿Y el primer pensamiento es WTF? ¿Cómo transferir esto a docker-compose?

Todo es bastante fácil. De hecho, esta línea indica los mismos parámetros que en el archivo yaml, solo abreviado. Por ejemplo, -e es un entorno en el que se pasan varios parámetros, también puede haber entradas como -p: estos son puertos que se llaman puertos en yaml. En consecuencia, para utilizar una imagen desconocida de una manera de calidad, solo necesita "googlear" la ventana acoplable para ejecutar abreviaturas y aplicar los nombres completos en el archivo yaml.

Ahora volvamos a docker-compose.yml, que cité como muestra arriba.

Este ejemplo usa mi imagen php7.2 hecha como una extensión para la imagen oficial php7.2-fpm-alpine, pero si no necesita tantas bibliotecas adicionales, puede construir su extensión para la imagen oficial y usarla. El resto de las imágenes para LAN son completamente originales y oficiales.

imagen : indique qué imagen descargar. Por ejemplo (rabbitmq: 3.7.7-management-alpine).

puertos : especifique los puertos que usará el contenedor (consulte la documentación de la imagen). El puerto nginx de ejemplo es 80 por defecto. En consecuencia, si desea utilizar el puerto 80, debe especificar 80:80 aquí y su sitio estará disponible en localhost. O puede especificar 7777: 80, y luego su sitio estará en url localhost: 7777. Esto es necesario para que se puedan implementar varios proyectos en el mismo host.

volúmenes : los directorios compartidos se indican aquí. Por ejemplo, su proyecto se encuentra en el directorio ~ / projects / my-sf4-app, y el contenedor php está configurado para funcionar con el directorio / app (igual que en / var / www / my-sf4-app). En consecuencia, sería conveniente que el contenedor tenga acceso al proyecto. En consecuencia, en volúmenes escribimos ~/projects/my-sf4-app:/app (vea este ejemplo en docker-compose.yml arriba (lo he indicado de manera relativa ../:/app)).

Por lo tanto, la carpeta se compartirá para el contenedor y podrá realizar varias acciones en ella como php bin/console doctrine:migrations:migrate . También es conveniente usar estos directorios para guardar los datos de la aplicación. Por ejemplo, postgresql, puede especificar un directorio para almacenar datos de la base de datos, y luego, cuando vuelva a crear el contenedor, no necesitará rodar un volcado o accesorios.

working_dir : indica el directorio de trabajo del contenedor. En este caso, / app (o por analogía con el vagrant / var / www / my-sf4-app).

entorno : todas las variables para el contenedor se pasan aquí. Por ejemplo, para rabbitmq, se transmiten el nombre de usuario y la contraseña, para postgresql, se pasan el nombre base, el nombre de usuario y la contraseña.

nombre_contenedor es un campo opcional, pero prefiero especificarlo, por la conveniencia de conectarse a los contenedores. Si no se especifica, se asignarán nombres predeterminados con hashes.

Estos son los parámetros principales que deben especificarse. El resto puede ser opcional para configuraciones adicionales, o de acuerdo con la documentación del contenedor.

Ahora, para comenzar todo esto, debe ejecutar el docker-compose up -d en el directorio donde se encuentra el archivo docker-compose.

¿Cómo y dónde almacenar todo esto para LAN?


Para LAN, uso la carpeta acoplable en la raíz del proyecto.


Contiene la carpeta de datos en la que almaceno toda la información postgresql y elasticsearch, para que cuando vuelva a crear el proyecto, no tenga que rodar los accesorios desde cero. También hay un nginx daddy en el que almaceno la configuración para el contenedor nginx local. Sincronizo estas carpetas en docker-compose.yml con los archivos y carpetas correspondientes en los contenedores. También en mi opinión, es muy conveniente escribir scripts de bash para trabajar con docker. Por ejemplo, el script start.sh inicia los contenedores, luego instala el compositor, limpia el caché y migra. También es conveniente para los colegas del proyecto, no tienen que hacer nada, solo ejecutan el script y todo funciona.

Ejemplo de script Start.sh

 #!/usr/bin/env bash green=$(tput setf 2) toend=$(tput hpa $(tput cols))$(tput cub 6) echo -n '   ?: ' read name echo "  $name!       tutmesto.ru" echo -n "$name,      ? (y/n): " read use_dump echo '    !' docker-compose up -d || exit echo -en '\n' echo -n "  ! ${green}${toend}[OK]" echo -en '\n' echo '    .' ./composer-install.sh echo -en '\n' echo -n "   ${green}${toend}[OK]" echo -en '\n' echo '     40 ,    postgres-' sleep 5 echo '  35 ...' sleep 5 echo '  30 ...' sleep 5 echo '  25 ...' sleep 5 echo '  20 ...' sleep 5 echo '  15 ...' sleep 5 echo '  10 ...' sleep 5 echo '  5 ...' sleep 5 echo ' .   postgres-        !' case "$use_dump" in y|Y) ./dump.sh echo -en '\n' echo -n "  ! ${green}${toend}[OK]" echo -en '\n' ;; *) echo "$name, ,   ! =)" ;; esac echo '    !' ./migrations-migrate.sh echo -en '\n' echo -n "  ! ${green}${toend}[OK]" echo -en '\n' echo '  !' ./php-fpm-command.sh rm -rf var/cache/* ./php-fpm-command.sh chmod 777 var/ -R ./cache-clear.sh echo -en '\n' echo -n "  ! ${green}${toend}[OK]" echo -en '\n' echo '    !' ./env.sh echo -en '\n' echo -n "   ! ${green}${toend}[OK]" echo -en '\n' echo ", $name,    !    localhost:7777  !" echo -en '\n' echo "------------------------------------------------------------------------------" echo -en '\n' echo "    :" echo "./cache-clear.sh |  symfony 4" echo "./composer.sh [command(ex. install)] |  " echo "./composer-install.sh | composer install" echo "./connect-to-php-fpm.sh |   php" echo "./console.sh [command(ex. cache:clear)] |  php bin/console" echo "./destroy.sh |  .    ." echo "./dump.sh | ,     (dump.sql)" echo "./env.sh |   " echo "./migrations-migrate.sh | " echo "./php-fpm-command.sh [command(ex. php -m)] |   php-fpm " echo "./start.sh |  ( )" echo "./stop.sh |Gracefull shutdown " echo -en '\n' echo "        :" echo "client@c.cc | QWEasd123" echo "admin@a.aa | QWEasd123" echo "moderator@m.mm | QWEasd123" echo -en '\n' echo "------------------------------------------------------------------------------" echo -en '\n' echo -en '\n' echo 'OtezVikentiy brain corporation!' echo -en '\n' echo -en '\n' 

Ejemplo de script Php-fpm-command.sh

 #!/usr/bin/env bash cd "`dirname \"$0\"`" && \ docker-compose exec -T "php-fpm" sh -c "cd /app && $*" 

Ejemplo de script Connect-to-php-fpm.sh

 #!/usr/bin/env bash docker exec -i -t --privileged php-fpm bash 

El entorno de desarrollo local termina aquí. ¡Felicitaciones, puede compartir el resultado final con sus colegas! )

Productiva


Preparación


Suponga que ya escribió algo en una LAN y desea ponerlo en un servidor de producción o en un servidor de prueba. Tiene alojamiento en virtualización KVM o su servidor en la habitación contigua con aire acondicionado.

Para implementar un producto o beta, el servidor debe tener un sistema operativo (idealmente Linux) y un Docker instalado. Docker se puede instalar de la misma manera que en LAN, no hay diferencias.

Docker en productividad es ligeramente diferente de LAN. En primer lugar, no puede simplemente tomar y especificar contraseñas y otra información y componer la ventana acoplable. En segundo lugar, no puede usar docker-compose directamente.

Docker utiliza el enjambre de docker y la pila de docker para la productividad. Si está justo en los dedos, entonces este sistema difiere solo en otros comandos y en ese docker swarm hay un equilibrador de carga para el clúster (nuevamente un poco abstracto, pero será más fácil de entender).

PD: te aconsejo que practiques la configuración de Docker Swarm en Vagrant (no importa lo paradójico que pueda parecer). Una receta simple para el entrenamiento: tome un Vagrant vacío con el mismo sistema operativo que el producto y configúrelo para que comience.

Para configurar el enjambre de Docker, solo necesita ejecutar algunos comandos:

 docker swarm init --advertise-addr 192.168.***.** (ip-  ) mkdir /app (          app) chown docker /app (     ) docker stack deploy -c docker-compose.yml my-first-sf4-docker-app 

Ahora consideramos todo esto con un poco más de detalle.

docker swarm init --advertise-addr - lanza docker swarm directamente y confunde un enlace para que pueda conectar algún otro servidor a este "enjambre" para que funcionen en el clúster.
mkdir / app && chown .. : debe crear todos los directorios necesarios para que la ventana acoplable funcione con anticipación para que durante la compilación no se queje de la falta de directorios.
docker stack deploy -c docker-compose.yml my-first-sf4-docker-app : este comando inicia el ensamblaje de su aplicación, un análogo de docker-compose up -d solo para el enjambre de docker.

Para iniciar cualquier ensamblaje, necesita el mismo docker-compose.yaml, pero ya está ligeramente modificado específicamente para productivo / beta.

 version: '3.1' services: php-fpm: image: otezvikentiy/php7.2-fpm:0.0.11 ports: - '9000:9000' networks: - my-test-network depends_on: - postgres - rabbitmq volumes: - /app:/app working_dir: /app deploy: replicas: 1 restart_policy: condition: on-failure placement: constraints: [node.role == manager] nginx: image: nginx:1.15.0 networks: - my-test-network working_dir: /app ports: - '80:80' depends_on: - php-fpm volumes: - /app:/app - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf deploy: replicas: 1 restart_policy: condition: on-failure placement: constraints: [node.role == manager] postgres: image: postgres:9.6 ports: - '5432:5432' working_dir: /app networks: - my-test-network secrets: - postgres_db - postgres_user - postgres_pass environment: POSTGRES_DB_FILE: /run/secrets/postgres_db POSTGRES_USER_FILE: /run/secrets/postgres_user POSTGRES_PASSWORD_FILE: /run/secrets/postgres_pass volumes: - ./data/dump:/app/dump - ./data/postgresql:/var/lib/postgresql/data deploy: replicas: 1 restart_policy: condition: on-failure placement: constraints: [node.role == manager] rabbitmq: image: rabbitmq:3.7.5-management networks: - my-test-network working_dir: /app hostname: my-test-sf4-app-rabbit-mq volumes: - /app:/app ports: - '5672:5672' - '15672:15672' secrets: - rabbitmq_default_user - rabbitmq_default_pass - rabbitmq_default_vhost environment: RABBITMQ_DEFAULT_USER_FILE: /run/secrets/rabbitmq_default_user RABBITMQ_DEFAULT_PASS_FILE: /run/secrets/rabbitmq_default_pass RABBITMQ_DEFAULT_VHOST_FILE: /run/secrets/rabbitmq_default_vhost deploy: replicas: 1 restart_policy: condition: on-failure placement: constraints: [node.role == manager] elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:6.3.0 networks: - my-test-network depends_on: - postgres environment: - discovery.type=single-node - discovery.zen.ping.unicast.hosts=elasticsearch - bootstrap.memory_lock=true - ES_JAVA_OPTS=-Xms512m -Xmx512m ports: - 9200:9200 - 9300:9300 working_dir: /app volumes: - /app:/app - ./data/elasticsearch:/usr/share/elasticsearch/data deploy: replicas: 1 restart_policy: condition: on-failure placement: constraints: [node.role == manager] jenkins: image: otezvikentiy/jenkins:0.0.2 networks: - my-test-network ports: - '8080:8080' - '50000:50000' volumes: - /app:/app - ./data/jenkins:/var/jenkins_home - /var/run/docker.sock:/var/run/docker.sock - /usr/bin/docker:/usr/bin/docker deploy: replicas: 1 restart_policy: condition: on-failure placement: constraints: [node.role == manager] volumes: elasticsearch: postgresql: jenkins: networks: my-test-network: secrets: rabbitmq_default_user: file: ./secrets/rabbitmq_default_user rabbitmq_default_pass: file: ./secrets/rabbitmq_default_pass rabbitmq_default_vhost: file: ./secrets/rabbitmq_default_vhost postgres_db: file: ./secrets/postgres_db postgres_user: file: ./secrets/postgres_user postgres_pass: file: ./secrets/postgres_pass 

Como puede ver, el archivo de configuración del producto es ligeramente diferente del archivo de LAN. Agregó secretos, despliegues y redes.

secretos : archivos para almacenar claves. Las claves se crean de manera bastante simple. Creas un archivo con el nombre de la clave: escribe el valor dentro. Después de eso, en docker-compose.yml especifica la sección de secretos y transfiere la lista completa de archivos con claves. Más detalles
redes : esto crea una determinada red interna a través de la cual los contenedores se comunican entre sí. En LAN, esto se hace automáticamente, pero de manera productiva, esto debe hacerse un poco de forma manual. Además, puede especificar configuraciones adicionales, excepto las predeterminadas. Más detalles
La implementación es la principal diferencia entre LAN y Producto / Beta.

  deploy: replicas: 1 restart_policy: condition: on-failure placement: constraints: [node.role == manager] 

Conjunto mínimo de luchador:

réplicas : indique la cantidad de réplicas que necesita ejecutar (de hecho, esto se usa si tiene un clúster y usa el equilibrador de carga desde la ventana acoplable). Por ejemplo, tiene dos servidores y los conectó a través del enjambre Docker. Al especificar el número 2 aquí, por ejemplo, se creará 1 instancia en 1 servidor y la segunda en el segundo servidor. Por lo tanto, la carga en el servidor se dividirá a la mitad.
restart_policy : la política de "volver a subir" automáticamente el contenedor en caso de que se caiga por algún motivo.
colocación : la ubicación de la instancia del contenedor. Por ejemplo, hay momentos en los que desea que todas las instancias de un contenedor giren solo en 1 de 5 servidores, y no se distribuyan entre ellos.

¡Quiero leer la documentación!

Entonces, hemos mejorado un poco lo que distingue a docker-compose.yaml para LAN de la versión del producto / beta. Ahora intentemos manejar este negocio.

Supongamos que está entrenando en Vagrant y en la raíz del servidor ya tiene el archivo configurado para el producto docker-compose.yml

 sudo apt-get update sudo apt-get -y upgrade sudo apt-get install -y language-pack-en-base export LC_ALL=en_US.UTF-8 export LANGUAGE=en_US.UTF-8 export LANG=en_US.UTF-8 curl -sSl https://get.docker.com/ | sh sudo usermod -aG docker ubuntu sudo apt-get install git sudo docker swarm init --advertise-addr 192.168.128.77 sudo mkdir /app sudo chmod 777 /app -R docker stack deploy -c /docker-compose.yml my-app git clone git@bitbucket.org:JohnDoe/my-app.git /app docker stack ps my-app docker stack ls docker stack services my-app 

PD: no patees por sudo y 777, por supuesto, no vale la pena hacerlo de manera productiva. Esto es solo para aprender velocidad.

Por lo tanto, estamos más interesados ​​en las líneas asociadas con la ventana acoplable.
Primero inicializamos el "enjambre" (enjambre de docker).
Luego creamos los directorios necesarios para el trabajo.
Descargue el nabo con nuestro código SF4 en el directorio / app.
Después de eso hay tres comandos: ps, ls y servicios.

Cada uno de ellos es útil a su manera. Utilizo ps con mayor frecuencia, ya que muestra el estado de los contenedores y parte del error, si corresponde.

Digamos que los contenedores se han elevado, pero algunos de ellos se bloquean constantemente con un error y en docker stack ps my-app ves un montón de reinicios. Para ver el motivo de la caída, debe ejecutar docker container ps -a, y aparecerá un contenedor que cae constantemente. Habrá muchas instancias del mismo contenedor, por ejemplo my-app_php-fpm.1. * Algún hash feroz *.

En consecuencia, ahora, conociendo el nombre del contenedor, ejecute los registros de Docker my-app_php-fpm.1. * Algún hash feroz * y mire a través de los registros. Corrija el error y reinicie TODO. Para golpear todos los contenedores, puede hacer esto:

 docker stack rm my-app 

Después de eso, tendrás un enjambre limpio sin ningún contenedor. Solucione el error, y de nuevo docker stack deploy -c docker-compose.yml my-app.

Source: https://habr.com/ru/post/es420673/


All Articles