• Как правильно делать deploy с помощью docker registry?

    Tyranron
    @Tyranron
    Официальную документацию надо все же читать, проявив усидчивость. Тогда не будет путаницы в базовых понятиях, из-за которой возникает каша в голове.

    Давайте разберемся с инструментами и их предназначением, которые Вы используете:
    • Комманда docker - это консольный интерфейс (CLI) для работы с Docker
    • docker build создает по заданному Dockerfile образ контейнера
    • docker tag присваивает указанному образу указанный тег (опция -t для build делает то же самое)
    • docker pull скачивает указанный образ из удаленного регистра на текущую машину
    • docker push заливает указанный образ в удаленный регистр
    • docker run запускает новый контейнер из указанного образа
    • docker ps выводит список текущих "бегущих" контейнеров

    Команда docker не жонглирует файлами, она жонглирует образами и контейнерами, а они от нас абстрагированы Docker'ом, как что-то эфемерное. То есть выполняя комманду docker pull Вы не скачиваете образ в ту папку, где выполняете команду, и уж точно не скачиваете какие-либо файлы. Все что Вы делаете этой командой - это скачиваете образ в локальное хранилище Docker'а, дабы Docker daemon мог запустить контейнер на основании этого образа.

    Команда docker-compose - это уже совсем другая команда. Все что она делает - это читает указанный YAML-манифест и выполняет соответствующие команды Docker. Это всего лишь позволяет декларативно указывать желаемые сценарии при работе с Docker в удобном формате. Но ни команда docker, ни docker-compose, не предоставляют ничего для того, чтобы транспортировать/обновлять версии Ваших манифестов где-то там. Docker, опять таки, жонглирует образами и контейнерами, не более.

    У Вас в манифесте указана директива build:. Таким образом docker-compose пытается сначала собрать контейнер, вместо того, чтобы просто запустить его из образа.

    Касательно совета docker-compose.yml под каждый env, все правильно советовали. Именно так это и задумывалось. Вы в манифесте указываете отнюдь не разные окружения (development, production), а набор контейнеров, которые должны бежать в одной связке одной логической единицей (концепция POD'ов). Ничего не запрещает делать и так, как сделали Вы, но это сродни использованию дуршлага в роли миски для еды: сегодня Вы нормально из него наворачиваете пельмени, а завтра супчик в нем уже куда-то не туда утекает.

    Воркфлоу в Вашем случае можно организовать следующим образом:
    1. На dev-машине у Вас один docker-compose.yml, согласно которому контейнер перед запуском собирается из сорцов.
    2. Когда у Вас готова новая версия приложения, Вы его собираете через docker build, присваиваете ему номер версии через docker tag и отправляете в удаленный регистр образов через docker push.
    3. На prod-машине у Вас отдельный docker-compose.ymlв котором указано запускать конкретную версию образа (и никаких build). Новая версия приложения - меняем тег образа в манифесте и перезапускаем контейнеры. При выполнении docker-compose образ автоматически скачается перед запуском, если его нет локально. Если же Вы обновили образ конкретной версии, которая уже была скачана ранее, то да, нужно выполнить docker pull перед стартом, дабы скачать новый образ.


    Дополнительный совет:
    Сборку образа и его заливку в удаленный регистр часто удобно автоматизировать с помощь Makefile'ов.
    Ответ написан
    3 комментария
  • Как правильно скрестить docker контейнеры?

    Tyranron
    @Tyranron
    Все зависит от модели взаимодействия между apache и php, которая Вам требуется.
    Грубо говоря: сколько процессов - столько и контейнеров.

    Если присмотреться к версиям образов php, то можно увидеть, что они предоставляют собой различные инструменты (смотрим на CMD в Dockerfile). Так, например, 7.0-fpm образ представляет собой процесс php-fpm демона. А вот 7.0-cli это просто запуск php-интерпретатора в интерактивном режиме (php -a). Версия 7.0-apache вообще являет собою Apache сервер, который умеет запускать php-скрипты.

    Соответственно, если Вам нужна модель Apache + php-fpm, значит берем контейнер apache и вяжем с контейнером php:fpm. Если Вам нужно, чтобы Apache напрямую запускал php-скрипты, берем один контейнер php:apache.
    Ответ написан
    Комментировать
  • Как в Dockerfile настроить Environment?

    Tyranron
    @Tyranron
    Закиньте megacopy комманду в задачник cron'а и запустите crond главным процессом контейнера (чтобы бежал в foreground).
    Вот пример под alpine.
    Ответ написан
    Комментировать
  • Как настроить подключение к базе на хосте из контейнера?

    Tyranron
    @Tyranron
    Пробросить контейнеру app через переменные окружения (environment variables) хост, логин и пароль для доступа к БД. В коде app взять параметры подключения к БД из проброшенных переменных окружения.
    Либо, подмонтировать в volumes папку с unix-сокетом базы данных и в коде app подключится к этому сокету. Но это будет работать только тогда, когда БД и app строго на одной машине.
    Ответ написан
    4 комментария
  • Docker как панацея для разработчика?

    Tyranron
    @Tyranron
    Для начала нужно понять "контейнер" и "контейнеризацию".
    Контейнеризируя процесс, мы его изолируем в своей среде, со своим личным user space. При этом ядро ОС (kernel) при работе контейнера используется то же самое, что и у основной ОС машины.

    Выгода здесь в том, что к контейнерам можно относиться как к этаким "бинарникам", грубо говоря. У Вас есть какое-то приложение, не важно какое-оно, будь то набор скриптов на PHP, либо уже скомпилированное что-то (postfix, nginx, apache, и т.п.). Вы это приложение и все его зависимости упаковываете в контейнер (создаете image) и на выходе получаете единое готовое "что-то", что Вы можете запустить и оно не требует более никаких зависимостей (кроме рантайма контейнеров - Docker, rkt, и т.п.). Полная аналогия с тем, как из вороха либ и исходников Вы компилите единый бинарник, который просто потом запускаете где хотите, без необходимости иметь исходники.
    Как мы привыкли в менеджерах зависимостей (composer, bower, другие) описывать и фиксировать зависимости исходного кода, так же и в контейнере мы делаем то же самое, но для окружения нашего приложения. Reproducibility во все поля.

    Это очень сильно упрощает жизнь. Вам больше не нужно заботиться о том, что для приложения нужно точно воспроизводить окружение на каждой машине, оно у Вас зафиксировано внутри контейнера. Никаких больше конфликтов между различными версиями jvm, php, python, ruby, nginx и т.д. Вы легко на одной и той же машине используете какие хотите приложения, каких хотите версий. Выкатка его же на другую машину больше не требует филигранной подгонки и согласования окружения в соответствие. У Вас больше не отвалится внезапно приложение, из-за недонастроенных апдейтов ОСи и внезапного обновления зависимых либ.

    А что Docker?
    Docker - это набор инструментов для работы с контейнерами.
    Docker daemon являет собой рантайм контейнеров, он их запускает, останавливает, отслеживает.
    Docker registry - это контроль версий созданных образов (images) приложения, по аналогии к контролю версий исходников приложения.

    Все. Концептуально ничего более Docker и контейнеризация не дают.

    Отвечая на Ваши вопросы:


    1. docker-daemon - это HTTP-сервер и он может взять на себя это работу на стороне сервера, т.е. nginx не нужен

      Нет. Docker daemon - это рантайм контейнеров. Он умеет "слушать" на определенных портах, но это сделано для взаимодействия с Docker runtime'ом, а не для выполнения функциональности HTTP-сервера. HTTP-сервер все ещё нужен, и он может (а по-хорошему и должен) быть запущен внутри контейнера.


    2. docker на дев-машине можно (как-то) связать с докером на хостинге

      Мы не жонглируем docker'ами. Docker - всего лишь инструмент для работы с контейнерами. Мы жонглируем контейнерами и приложениями, упакованными в них. Нет смысла связывать docker'ы на хостинге и на дев-машине. Вы создаете образ (image) и можете его запускать через docker как на дев-машине, так и на хостинге. Если Вам нужно, чтобы одни приложения на дев-машине общались с другими на хостинге, то это не вопрос к docker'у - это вопрос к организации связи между Вашими приложениями.


    3. и учитвыая предудущий пункт - docker можно использовать для деплоя

      ИМХО, нужно. Вы закатали в образ точную версию приложения и его окружения. Осталось теперь этот "бинарник" запустить где хочется.


    4. docker можно использовать для отката, если деплой не задался

      Легко. Просто тушим контейнер нового образа и подымаем обратно старый.


    5. пропадает необходимость в во всяких rbenv и pyenv, если нужна другая версия языка, то просто создается новый контейнер в котором и происходит установка

      Да. Вы в Dockerfile, по сути, точно декларируете свое окружение. Нужно другое окружение - меняем Dockerfile и создаем новый образ.


    6. докер очень быстрый, в т.ч. старты и рестарты

      Не понятно - быстрый в чем? Наверное, имеется в виду сравнение с виртуальными машинами. Да, накладные расзоды меньше, нежели у виртуалок, так как используется одно и то же ядро ОС. Просто процессы запускаются в разных user space'ах. В остальном скорость Docker - это скорость запуска, собственно, процессов. Если у Вас тяжелое приложение с медленным стартом (привет, FMS!) или остановкой, то Docker тут Вам ничем не поможет.

    Ответ написан
    4 комментария
  • CoreOS + Kubernetes - рабочая схема?

    Tyranron
    @Tyranron
    Не смотря на то, что тред старый...
    Есть люди. И имеется успешный опыт. Есть желание им делиться.
    Задавайте конкретные вопросы здесь на Тостере, проставляя корректные теги.
    Ответ написан
    4 комментария
  • С чего начать изучать Dart?

    Tyranron
    @Tyranron
    Имхо, официального сайта более чем достаточно для "начать". Прохождение Language Tour и Library Tour уже Вас основательно познакомит с Dart'ом. Там же есть описание нужных инструментов для работы с Dart, а также официальный style guide. Этого должно быть достаточно для "сесть и начать писать код". Если же этого мало, то там же есть ссылки на статьи и книги для более губокого изучения. Ну и заправлено все это примерами кода. Что не говори, а дока у Dart'а отличнейшая!
    Касательно "на русском" - увы, не в курсе.
    Ответ написан
    Комментировать
  • Почему type []User нельзя использовать как type []UserInterface?

    Tyranron
    @Tyranron
    Это сделано намеренно, дабы избежать неявных дорогих преобразований.

    Первое, что нужно знать — это отличия «структуры» от «интерфейса» в Go. Это просто, и этого достаточно, чтобы понять, почему вы просто так не можете «скастить» слайс структур в слайс интерфейсов.
    ...
    Второе — и созвучное с выше обсужденными слайсами — это то, операция конвертирования слайсов — дорогая операция. По времени это O(n) и компилятор Go подобные дорогие вещи не будет делать, чтобы не давать нерадивым программистам писать медленный код. Хотите делать потенциально дорогую операцию — будьте добры, сделайте это явно, вся ответственность на вас, а не на компиляторе.

    Детальнее:
    Холиворная статья: причина №4
    Объяснение на SO
    Ответ написан
    Комментировать
  • Перспективы у языка GO?

    Tyranron
    @Tyranron
    По поводу сложности языка.
    Просто оставлю это здесь.
    Ответ написан
    2 комментария
  • В чем проблема отправки сигнала дочернему процессу?

    Tyranron
    @Tyranron
    Извините за прямоту, но проблема в недостаточном знании Вами матчасти.
    Что почитать по теме: Zombie process, а также Docker and the PID 1 zombie reaping problem.

    А теперь ближе к Вашему примеру.
    Cуть: и SITERM'ом, и SIGKILL'ом Вы child процесс успешно убиваете, после чего он превращается в зомби-процесс, то есть все еще висит в памяти под своим PID ожидая reaping (системного вызова wait() от parent процесса). После завершения parent процесса наш зомби-child усыновляется init процессом, который его и reap'ит.
    Если запустить Ваши программы в том виде, котором Вы их запостили, и во время тиканья написать ps, то увидим следующую картину:
    459 ttys000    0:00.03 -bash
    498 ttys000    0:00.00 ./parent
    499 ttys000    0:00.00 (child)
    То, что child указан в скобках, как раз и означает, что процесс был остановлен (то есть он совершил системный вызов exit()) и ожидает reaping'а (когда результат exit()'а прочтут wait()'ом).
    Если перед посылкой child'у добавитьtime.Sleep(10 * time.Second) и сразу после вывода child'овского PID'а набрать глянуть что творится в процессах, то увидим такую картину:
    459 ttys000    0:00.04 -bash
    510 ttys000    0:00.00 ./parent
    511 ttys000    0:00.00 ./child
    Сравните с тем как он отображается в процессах после того, как был убит.
    А если мы после посылки сигнала child'у добавимcmd.Process.Wait(), то Ваш цикл ticker'а все равно, возможно, еще будет крутится, если в системе появился новый процесс с таким PID'ом, но если при этом заглянуть в ps, то увидим, что нашего child'а уже нет совсем:
    459 ttys000    0:00.05 -bash
    536 ttys000    0:00.01 ./parent

    Кстати, о волшебной силе Process.Wait() пишется прямо в его доке.
    Ответ написан
    1 комментарий
  • Как бы вы сделали проверку на запуск второго экземпляра программы?

    Tyranron
    @Tyranron
    Мне не нравится 3й вариант, так как он не решает задачу целиком. Порт, который слушать - это больше конфигурационный параметр, значит надо задумываться уже, ничего ли страшного не случится при смене порта и рестарте (обычно не должно, но раз на раз не приходится). А что, если демону и вовсе не нужно слушать какой-либо порт? Не универсальненько.

    Увы, кросс-платформенного решения "из коробки" нет, да. Я когда стряпал свою поделку, то меня интересовали только *nix-like платформы, мне хватило старого хорошего PID-файла с syscall.Flock. То, что видел в других решениях, более кросс-платформенных, - люди заморачивались на platform specific код, для Windows они использовали регистрацию процесса в виде сервиса. Обернуть это дело в отдельный пакет с единым интерфейсом и platform specific компиляцией совсем не сложно в случае с Go. Для работы с сервисами Windows есть замечательный, пусть и не входящий в стандартную либу, но все же официальный пакет golang.org/x/sys/windows/svc, и костылить на чистых syscall'ах даже не нужно.
    Также загляните в этот тред, там как раз про решение для Windows в виде semaphore/mutex аналогично тому, что указал Владимир Мартьянов в комментарии к Вашему вопросу и тому, что Вы указали 2м пунктом.
    Ответ написан
    Комментировать
  • Как сконвертить [4]uint8{0,0,0,0} в []uint8{}?

    Tyranron
    @Tyranron
    Касаемо вопроса:
    Ну Вы бы доки хотя бы поглядели, ситуёвина то детская. Здесь конкретно по Вашему вопросу.
    x := [3]string{"Лайка", "Белка", "Стрелка"}
    s := x[:] // a slice referencing the storage of x


    Касаемо чесаной репки:
    ИМХО, не стоит делать versus. И на том, и на другом языке эта задача замечательно решается.
    Go очень хорош и удобен для написания демонов. Наверное, можно сказать, что фактически это его основная ниша сейчас.
    Rust более низкоуровневый, но, и в то же время, гораздо интереснее и выразительнее Go.
    Если проект домашний и есть интерес поколошматить мозги об Rust, то я бы выбрал его. Если надо быстро, легко, удобно и понятно (не только Вам), то, конечно же Go и не заморачивался бы.
    Ответ написан
  • Как в Stylus разбить длинное правило на несколько строк?

    Tyranron
    @Tyranron
    По идее так:
    body
      background: rgba(121, 175, 11, 0.5) \
        url('../files/img/dish-check.svg') \
        no-repeat center center
    Проверял здесь, вроде работает.

    Если изначально было разделено запятыми, то можно просто переносить на следующую строку, аля:
    -webkit-box-shadow: 1px 0 0 rgba(  0,  0,  0,.2)
                        2px 0 0 rgba(255,255,255, 4)
    Ответ написан
    Комментировать
  • Можете помочь с одним регулярным выражением?

    Tyranron
    @Tyranron
    Вы можете дополнить регулярку своей логикой в PHP.
    function replaceSpacesWithTabs($line, $perTab = 2)
    {
        return preg_replace_callback('/^[ ]+/', 
            function ($matches) use ($perTab) {
                $len = strlen($matches[0]);
                $out = str_repeat("\t", floor($len / $perTab));
                if (($rem = $len % $perTab) > 0) {
                    $out .= str_repeat(' ', $rem);
                }        
                return $out;
            },
            $line
        ); 
    }

    Потыкать можно здесь.

    На решение чисто регуляркой, по моему мнению, не тянет. Но применить можно вполне себе.
    Ответ написан
    Комментировать
  • Зачем в PHP нужна рефлексия?

    Tyranron
    @Tyranron
    Еще с помощью нее делают удобние IoC-контейнеры, например, в Laravel.
    А еще она позволяет тестировать private методы классов напрямую.
    В общем-то, дальше дело фантазии, рефлексия всего лишь позволяет программе отслеживать свою структуру и поведение во время выполнения.
    Ответ написан
    2 комментария
  • Как устроен asp.net?

    Tyranron
    @Tyranron
    MSDN?
    Ответ написан
    Комментировать
  • НЕ http фреймворк, похожий на RoR - делать или уже есть?

    Tyranron
    @Tyranron
    На Ruby не знаю, есть ли. Это лучше спросить на SO или в тематических Google Groups. Там людей больше, точно накидают пищи к размышлениям.

    Если не на Ruby, то знаю хороший Go проект Gobot.
    Ответ написан
    2 комментария
  • Какие существуют на данный момент open-source сервера Git с Web-интерфейсом?

    Tyranron
    @Tyranron
    Еще посмотрите на Gogs. Тот же Gitlab, только на Go, а соответственно и с минимальными зависимостями и системными требованиями.
    Ответ написан
    Комментировать
  • Репликация в MySql?

    Tyranron
    @Tyranron
    Зависит от настроек репликации.
    Что в my.cnf master'а указано под replicate-do-db, то и будет реплицироваться.
    Подробнее читайте здесь и в официальной доке.
    Ответ написан
    Комментировать
  • Выбор функционального языка программирования?

    Tyranron
    @Tyranron
    Если под "функциональным" подразумевается функциональная парадигма, то Go тут явно аутсайдер. Советую Haskell для ознакомления с парадигмой фактически в "чистом" виде. После него - Scala и/или Rust, как удачные смешения функциональной парадигмы с другими парадигмами/направлениями. И не забудьте повертеть Erlang.

    Если же под "функциональным" подразумевается удобный инструмент с многими возможностями из коробки, то тут однозначно Go, так как и порог вхождения мал, и прививает хорошие практики. После него Scala + FRP + TypesafeStack тоже должны показаться интересными, но там порог вхождения повыше будет.
    Ответ написан
    Комментировать