Задать вопрос
  • Как грамотно настроить общий ресурс между контейнерами?

    IgorPI
    @IgorPI Автор вопроса
    Сергей, Вы были правы!

    В точку
    open_file_cache max=100;

    Параметр был включен в контексте http.

    Выключил
    open_file_cache off;

    Теперь изображения не блокируются.
  • Как грамотно настроить общий ресурс между контейнерами?

    IgorPI
    @IgorPI Автор вопроса
    Контейнер в котором находятся изображения
    Debian GNU/Linux 10

    Контейнер в котором находятся приложение
    Ubuntu 18.04.3 LTS
  • Как грамотно настроить общий ресурс между контейнерами?

    IgorPI
    @IgorPI Автор вопроса
    Сергей, Файловая система

    # df -T
    Filesystem     Type          1K-blocks      Used Available Use% Mounted on
    overlay        overlay        61255652   2408348  55705972   5% /
    tmpfs          tmpfs             65536         0     65536   0% /dev
    tmpfs          tmpfs           1018508         0   1018508   0% /sys/fs/cgroup
    grpcfuse       fuse.grpcfuse 124372988 113400172  10972816  92% /www
    /dev/sda1      ext4           61255652   2408348  55705972   5% /etc/hosts
    shm            tmpfs             65536         0     65536   0% /dev/shm
    tmpfs          tmpfs           1018508         0   1018508   0% /proc/acpi
    tmpfs          tmpfs           1018508         0   1018508   0% /sys/firmware
    #


    Файлы лежат в /www
    Аналогичная в другом контейнере.

    Что касается lslocks, он не чего не показал.

    Замечу, работаю под Windows 10 pro
    Linux containers
  • Как грамотно настроить общий ресурс между контейнерами?

    IgorPI
    @IgorPI Автор вопроса
    server {
        listen                          80;
        client_max_body_size            208M;
        access_log                      /var/log/nginx/images.access.log combined;
        error_log                       /var/log/nginx/images.error.log error;
    
        location ~ \.(jpg|jpeg|png)$ {
            root                        /www/images;
        }
    }
  • Как грамотно настроить общий ресурс между контейнерами?

    IgorPI
    @IgorPI Автор вопроса
    Сергей, Круг подозреваемых сужается.
    Осталось выяснить, что же делает с моими файлами nginx.
  • Как грамотно настроить общий ресурс между контейнерами?

    IgorPI
    @IgorPI Автор вопроса
    # Php application
      app:
        container_name: rapp.app
        restart: on-failure
        build:
          context: .
          dockerfile: ./docker/php/Dockerfile-dev
        volumes:
          - ./:/www/
          - ./docker/php/log:/var/log
          - ./docker/php/usr/local/etc/php/conf.d:/usr/local/etc/php/conf.d
          - ./images:/www/images:rw
        depends_on:
          - db
        links:
          - db
        expose:
          - 9000
        environment:
          PHP_INI_SCAN_DIR: ":/usr/local/etc/php/conf.d"
          TZ: "Europe/Moscow"

    # ls -l
    total 0
    -rwxr-xr-x 1 root root  27384 Feb 10 03:10 9d38dd5b8c9e8707913fefe56c889304-5e409f7ccba8c.png
    -rwxr-xr-x 1 root root 222764 Feb 10 04:25 ce0f1f370e9884e65e8cc911cb8b93a9-5e40b11173598.jpeg
    -rwxr-xr-x 1 root root 222764 Jan  1  1970 ce0f1f370e9884e65e8cc911cb8b93a9-5e40c760c0e92.jpeg
    #
    #
    # unlink ce0f1f370e9884e65e8cc911cb8b93a9-5e40c760c0e92.jpeg
    unlink: cannot unlink 'ce0f1f370e9884e65e8cc911cb8b93a9-5e40c760c0e92.jpeg': Device or resource busy


    # Nginx api admin server
      nginx-images:
        container_name: rapp.nginx-images
        restart: on-failure
        image: nginx:latest
        volumes:
          - ./docker/nginx/dev/nginx.conf:/etc/nginx/nginx.conf
          - ./docker/nginx/dev/logs/nginx-images:/var/log/nginx
          - ./docker/nginx/dev/sites-enabled/vhost-images.conf:/etc/nginx/sites-enabled/vhost-images.conf
          - ./images:/www/images:ro
        ports:
          - 127.0.0.100:8013:80
        depends_on:
          - app
        expose:
          - 80
        command: ["nginx", "-g", "daemon off;"]


    # ls -l
    total 0
    -rwxr-xr-x 1 root root  27384 Feb 10 00:10 9d38dd5b8c9e8707913fefe56c889304-5e409f7ccba8c.png
    -rwxr-xr-x 1 root root 222764 Feb 10 01:25 ce0f1f370e9884e65e8cc911cb8b93a9-5e40b11173598.jpeg
    -rwxr-xr-x 1 root root 222764 Jan  1  1970 ce0f1f370e9884e65e8cc911cb8b93a9-5e40c760c0e92.jpeg
    #
    #
    # unlink ce0f1f370e9884e65e8cc911cb8b93a9-5e40c760c0e92.jpeg
    unlink: cannot unlink 'ce0f1f370e9884e65e8cc911cb8b93a9-5e40c760c0e92.jpeg': Read-only file system
  • Как грамотно настроить общий ресурс между контейнерами?

    IgorPI
    @IgorPI Автор вопроса
    Сергей, У меня до этого не было проблем, но и я не выполнял unlink файла.

    Контейнер номер 1.
    В нем я пытаюсь удалить файл

    Контейнер номер 2.
    Установлен только nginx, который только и делает, что раздаёт статику.

    У них общая директория
    Условно: /www/images

    Самое забавное, что если в браузере не запрашивать изображение, то Контейнер номер 1 без проблем удаляет файл и нет не каких блокировок. Стоит мне в браузере просмотреть это изображения — все, больше я не могу удалить этот файл с контейнера номер 1.
  • Как грамотно настроить общий ресурс между контейнерами?

    IgorPI
    @IgorPI Автор вопроса
    Обнаружил, при остановке контейнера nginx-images проблем не наблюдается. Но это же очевидно.

    Я пошел дальше, в конфиге nginx изменил корневую папку. Запустил контейнер.
    Снова проблем нет. Файлы не блокируются.

    Неужели nginx ставит эксклюзивную блокировку на раздаваемый файл?
  • Как синхронизировать правки рабочего кода не перезагружая приложение под docker-compose?

    IgorPI
    @IgorPI
    Я обновился до полдней версии докера.
    Аналогичная проблема.

    Временно решил проблему с помощь, File Watchers, встроенная возможность Phpstorm
    File Watchers позволяет запускать сторонний софт после изменения файлов.

    docker restart <container>
  • Eslint, как настроить правило начала строки?

    IgorPI
    @IgorPI Автор вопроса
    Алексей Уколов,
    "На последнем изображении" у вас красная линия. Мы как по ней должны догадаться в чём конкретно проблема?

    Как оказалось, эта ошибка отображалась только визуально, она не влияла на работу приложения.
    То есть в консоли не было сообщения.
  • Eslint, как настроить правило начала строки?

    IgorPI
    @IgorPI Автор вопроса
    Или например вот

    export function hasProperties (obj, property) {
      const properties = property.split(/\./)
      for (const prop in properties) {
        if ({}.hasOwnProperty.call(obj, properties[prop])) { return false }
      }
      return true
    }


    Сообщение: 'prop' is defined but never used no-unused-vars
  • Nodejs native в vue, как https сделать плагином?

    IgorPI
    @IgorPI Автор вопроса
    То есть если просто использовать Plugin вместо HttpsPlugin в некоторых случаях работать не будет.
  • Symfony, кто знает как замэппить значение из Request?

    IgorPI
    @IgorPI Автор вопроса
    BoShurik, Согласен. Так даже лучше.
  • Symfony контент в базе данных на нескольких языках?

    IgorPI
    @IgorPI Автор вопроса
    Сервис для автоматического перевода свойств

    <?php
    
    
    namespace App\Service;
    
    use App\Classes\Translatable\TranslationEntityInterface;
    use Doctrine\Common\Collections\ArrayCollection;
    use Doctrine\ORM\PersistentCollection;
    
    /**
     * Class EntityTranslation
     * @package App\Service
     */
    class EntityTranslation
    {
        /**
         * @param $entity
         * @param string $lang
         * @param array $properties
         * @return ArrayCollection
         */
        public function translate($entity, string $lang, $properties = [])
        {
            if (is_array($entity) or is_a($entity, PersistentCollection::class)) {
                return $this->translateCollection($entity, $lang, $properties);
            } elseif (is_a($entity, TranslationEntityInterface::class)) {
                $this->translateOneObject($entity, $lang, $properties);
            }
        }
    
        /**
         * @param $items
         * @param string $lang
         * @param array $properties
         * @return ArrayCollection
         */
        public function translateCollection($items, string $lang, $properties = [])
        {
            foreach ($items as $item) {
                foreach ($item->getTranslations($lang) as $translation) {
                    $item->setProperty($translation->getField(), $translation->getContent());
                }
    
                foreach ($properties as $property_name) {
                    if ($item->hasOwnProperty($property_name)) {
                        $this->translate($item->getProperty($property_name), $lang, []);
                    }
                }
            }
            return $items;
        }
    
        /**
         * @param TranslationEntityInterface $entity
         * @param string $lang
         * @param array $properties
         * @return TranslationEntityInterface
         */
        public function translateOneObject(TranslationEntityInterface $entity, string $lang, $properties = [])
        {
    
            foreach ($entity->getTranslations($lang) as $translation) {
                $entity->setProperty($translation->getField(), $translation->getContent());
            }
    
            foreach ($properties as $property_name) {
                if ($entity->hasOwnProperty($property_name)) {
                    $this->translate($entity->getProperty($property_name), $lang, []);
                }
            }
    
            return $entity;
        }
    }


    Как использовать?

    /**
         * @Route(
         *     path="/products.getCategories",
         *     methods={"GET"}
         * )
         * @param Request $request
         * @param EntityManagerInterface $manager
         * @param NormalizerInterface $normalizer
         * @param EntityTranslation $et
         * @param Lang $lang
         * @return JsonResponse
         * @throws ExceptionInterface
         */
        public function getCategories(
            Request $request,
            EntityManagerInterface $manager,
            NormalizerInterface $normalizer,
            EntityTranslation $et,
            Lang $lang
        )
        {
            /** @var CategoryProductRepository $categories_repository */
            $categories_repository = $manager->getRepository("App:CategoryProduct");
    
            $rs = new ResponseSchemaItems();
            $rs->setCount($categories_repository->count(["restaurant" => $request->get("restaurant_id")]));
    
            $categories = $categories_repository->getAll(
                $request->get("restaurant_id", 0),
                $request->get("q", ""),
                $request->get("offset", 0),
                $request->get("count", 100)
            );
    
            $et->translate($categories, $lang->get());
    
            $rs->setItems($categories);
    
            $response_object = $normalizer->normalize($rs, "json", [
                "attributes" => [
                    "code",
                    "count",
                    "items" => [
                        "id",
                        "name",
                        "description"
                    ]
                ]
            ]);
            return $this->json($response_object);
        }


    $et->translate($categories, $lang->get(), []);

    Глубина перевода будет зависеть от третьего параметра (массива свойств)
  • Symfony контент в базе данных на нескольких языках?

    IgorPI
    @IgorPI Автор вопроса
    Решение №2

    AbstractTranslation.php
    <?php
    
    namespace App\Classes\Translatable;
    
    
    use Doctrine\ORM\Mapping as ORM;
    
    /**
     * Class AbstractTranslation
     * @package App\Entity
     */
    abstract class AbstractTranslation
    {
    
        /**
         * @ORM\Id()
         * @ORM\GeneratedValue()
         * @ORM\Column(type="integer")
         */
        protected $id;
    
        /**
         * @ORM\Column(type="string", length=10)
         */
        protected $lang;
    
        /**
         * @var string $field
         * @ORM\Column(length=255)
         */
        protected $field;
    
    
        /**
         * @var string $content
         *
         * @ORM\Column(type="text", nullable=true)
         */
        protected $content;
    
        /**
         * Get id
         *
         * @return integer $id
         */
        public function getId()
        {
            return $this->id;
        }
    
        /**
         * @param string $locale
         * @return static
         */
        public function setLang(string $locale)
        {
            $this->lang = $locale;
            return $this;
        }
    
        /**
         * @return string|null
         */
        public function getLang(): ?string
        {
            return $this->lang;
        }
    
        /**
         * Set field
         *
         * @param string $field
         *
         * @return static
         */
        public function setField(string $field)
        {
            $this->field = $field;
            return $this;
        }
    
        /**
         * Get field
         *
         * @return string
         */
        public function getField()
        {
            return $this->field;
        }
    
        /**
         * @param string $content
         * @return static
         */
        public function setContent($content)
        {
            $this->content = $content;
            return $this;
        }
    
        /**
         * Get content
         *
         * @return string
         */
        public function getContent()
        {
            return $this->content;
        }
    }


    AbstractTranslationEntity.php
    <?php
    
    
    namespace App\Classes\Translatable;
    
    
    abstract class AbstractTranslationEntity
    {
        use PropertyManager;
    }


    PropertyManager.php
    <?php
    
    
    namespace App\Classes\Translatable;
    
    /**
     * Trait PropertyManager
     * @package App\Classes\Translatable
     */
    trait PropertyManager
    {
        /**
         * @param string $name
         * @param $value
         */
        public function setProperty(string $name, $value)
        {
            $this->{$name} = $value;
        }
    
    
        /**
         * @param string $name
         * @return
         */
        public function getProperty(string $name)
        {
            return $this->{$name};
        }
    
        /**
         * @param string $name
         * @return bool
         */
        public function hasOwnProperty(string $name)
        {
            return isset($this->{$name});
        }
    }


    TranslationEntityInterface.php
    <?php
    
    
    namespace App\Classes\Translatable;
    
    /**
     * Interface TranslationEntity
     * @package App\Classes\Entity
     */
    interface TranslationEntityInterface
    {
        /**
         * @param $entity
         * @return mixed
         */
        public function addTranslation($entity);
    
        /**
         * @param string $lang
         * @return mixed
         */
        public function getTranslations(string $lang);
    }


    TranslationInterface.php
    <?php
    
    
    namespace App\Classes\Translatable;
    
    /**
     * Interface TranslationInterface
     * @package App\Classes\Translatable
     */
    interface TranslationInterface
    {
    
        /**
         * @ORM\ManyToOne(targetEntity="Product", inversedBy="translations")
         * @ORM\JoinColumn(name="owner_id", referencedColumnName="id", onDelete="CASCADE")
         */
    
        /**
         * ProductTranslation constructor.
         * @param string $lang
         * @param string $field
         * @param $value
         */
        public function __construct(string $lang, string $field, $value);
    
        /**
         * @param $owner
         */
        public function setOwner($owner): void;
    
        /**
         * @return mixed
         */
        public function getOwner();
    }


    Сущности

    <?php
    
    
    namespace App\Entity;
    
    
    use App\Classes\Translatable\AbstractTranslationEntity;
    use App\Classes\Translatable\TranslationEntityInterface;
    use Doctrine\Common\Collections\ArrayCollection;
    use Doctrine\ORM\Mapping as ORM;
    use Symfony\Component\Validator\Constraints as Assert;
    
    /**
     * @ORM\Entity(repositoryClass="App\Repository\CategoryProductRepository")
     * @ORM\Table(name="categories_products")
     */
    class CategoryProduct extends AbstractTranslationEntity implements TranslationEntityInterface
    {
    
        /**
         * @ORM\Column(type="integer")
         * @ORM\Id
         * @ORM\GeneratedValue
         */
        private $id;
    
        protected $name;
    
        protected $description;
    
        /**
         * @var Image|null
         * @ORM\ManyToOne(targetEntity="App\Entity\Image", fetch="EXTRA_LAZY")
         * @ORM\Column(nullable=true)
         */
        private $image;
    
        /**
         * @var Restaurant
         * @Assert\NotNull
         * @ORM\ManyToOne(targetEntity="Restaurant", fetch="EXTRA_LAZY")
         */
        private $restaurant;
    
        /**
         * @var ArrayCollection
         * @ORM\OneToMany(
         *     targetEntity="CategoryProductTranslation",
         *     mappedBy="owner",
         *     cascade={"persist", "remove"},
         *     fetch="EXTRA_LAZY"
         * )
         */
        private $translations;
    
        /**
         * CategoryProduct constructor.
         */
        public function __construct()
        {
            $this->translations = new ArrayCollection();
        }
    
        /**
         * @return mixed
         */
        public function getId()
        {
            return $this->id;
        }
    
        /**
         * @return string|null
         */
        public function getName(): ?string
        {
            return $this->name;
        }
    
        /**
         * @return Image|null
         */
        public function getImage(): ?Image
        {
            return $this->image;
        }
    
        /**
         * @param Image|null $image
         */
        public function setImage(?Image $image): void
        {
            $this->image = $image;
        }
    
    
        /**
         * @return Restaurant|null
         */
        public function getRestaurant(): ?Restaurant
        {
            return $this->restaurant;
        }
    
        /**
         * @param Restaurant $restaurant
         */
        public function setRestaurant(?Restaurant $restaurant): void
        {
            $this->restaurant = $restaurant;
        }
    
        /**
         * @param $entity
         * @return CategoryProduct
         */
        public function addTranslation($entity)
        {
            if (!$this->translations->contains($entity)) {
                $this->translations[] = $entity;
                $entity->setOwner($this);
            }
            return $this;
        }
    
        /**
         * @param string $lang
         * @return ArrayCollection
         */
        public function getTranslations(string $lang)
        {
            $translations = new ArrayCollection();
            /** @var ProductTranslation $item */
            foreach ($this->translations->toArray() as $item) {
                if ($item->getLang() == $lang) {
                    $translations->add($item);
                }
            }
            return $translations;
        }
    
        /**
         * @return mixed
         */
        public function getDescription(): ?string
        {
            return $this->description;
        }
    }


    <?php
    
    
    namespace App\Entity;
    
    
    use App\Classes\Translatable\AbstractTranslation;
    use App\Classes\Translatable\TranslationInterface;
    use Doctrine\ORM\Mapping as ORM;
    
    /**
     * @ORM\Entity
     * @ORM\Table(name="categories_products_translations")
     */
    class CategoryProductTranslation extends AbstractTranslation implements TranslationInterface
    {
    
        /**
         * ProductTranslation constructor.
         * @param string $lang
         * @param string $field
         * @param $value
         */
        public function __construct(string $lang, string $field, $value)
        {
            $this->setLang($lang);
            $this->setField($field);
            $this->setContent($value);
        }
    
        /**
         * @ORM\ManyToOne(targetEntity="CategoryProduct", inversedBy="translations")
         * @ORM\JoinColumn(name="owner_id", referencedColumnName="id", onDelete="CASCADE")
         */
        protected $owner;
    
        /**
         * @param $owner
         */
        public function setOwner($owner): void
        {
            $this->owner = $owner;
        }
    
        /**
         * @return mixed
         */
        public function getOwner()
        {
            return $this->owner;
        }
    }
  • Symfony, кто знает как замэппить значение из Request?

    IgorPI
    @IgorPI Автор вопроса
    BoShurik, Ок. Спасибо.
    В своём проекте я разделил проект на отдельные ядра.