├── .tmux.conf ├── Dockerfile ├── bash_profile ├── boot2docker ├── Dockerfile ├── automount-shares.tpl └── build_iso.sh ├── id_rsa.pub ├── react ├── proposals.md └── readme.md ├── readme.md ├── ssh_config ├── tmuxexample ├── Dockerfile ├── id_deployment_key └── id_deployment_key.pub └── watch.md /.tmux.conf: -------------------------------------------------------------------------------- 1 | # force a reload of the config file 2 | unbind r 3 | bind r source-file ~/.tmux.conf 4 | unbind l 5 | bind l send-keys -R C-m\; clear-history 6 | 7 | setw -g mode-mouse on 8 | set -g mouse-resize-pane on 9 | set-option -g mouse-select-pane on 10 | set -g history-limit 100000 11 | set -g base-index 1 12 | set -g default-terminal "xterm-256color" 13 | setw -g aggressive-resize off 14 | 15 | set-option -g set-titles on 16 | set-option -g set-titles-string '#H:#S.#I.#P #W #T' # window number,program name, active(or not) 17 | 18 | #set-option -g default-command "reattach-to-user-namespace -l bash" 19 | 20 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | #основа ubuntu 14.04 и всякие полезняки 2 | FROM phusion/baseimage:0.9.13 3 | 4 | #сгенерить ключики 5 | RUN /etc/my_init.d/00_regen_ssh_host_keys.sh 6 | 7 | # Use baseimage-docker's init system. 8 | CMD ["/sbin/my_init"] 9 | 10 | 11 | 12 | # ...put your own build instructions here... 13 | #создать юзера с паролем cnerkjhtp, и папку .ssh 14 | RUN /usr/sbin/useradd --create-home --home-dir /home/ice --shell /bin/bash ice && \ 15 | echo "ice:cnerkjhtp" | chpasswd && \ 16 | usermod -aG sudo ice && \ 17 | mkdir -p /home/ice/.ssh && \ 18 | chown ice /home/ice/.ssh && \ 19 | chmod 700 /home/ice/.ssh 20 | 21 | #настроить переменные окружения 22 | ENV HOME /home/ice 23 | ENV LANG en_US.UTF-8 24 | ENV LC_ALL en_US.UTF-8 25 | 26 | #дадим доступ на чтение переменных окружения другим юзерам 27 | RUN chmod 644 /etc/container_environment.sh 28 | 29 | #добавим то что считаем нужным к ~/profile своего юзера см содержимое bash_profile 30 | ADD bash_profile /home/ice/.profile 31 | 32 | #откопировать конфигурацию тмукса 33 | ADD .tmux.conf /home/ice/.tmux.conf 34 | 35 | #откопировать публичные ключи тем кому можно 36 | ADD pub_keys/id_rsa_0.pub /tmp/id_rsa_0.pub 37 | ADD pub_keys/id_rsa_1.pub /tmp/id_rsa_1.pub 38 | ADD pub_keys/id_rsa_2.pub /tmp/id_rsa_2.pub 39 | 40 | RUN cat /tmp/id_rsa_0.pub /tmp/id_rsa_1.pub /tmp/id_rsa_2.pub >> /home/ice/.ssh/authorized_keys && rm -f /tmp/id_rsa.pub && \ 41 | chown ice /home/ice/.ssh/authorized_keys && \ 42 | chmod 600 /home/ice/.ssh/authorized_keys 43 | 44 | #запретить чеканье фингерпринта для bitbucket.org 45 | ADD ssh_config /home/ice/.ssh/config 46 | RUN chown ice /home/ice/.ssh/config && \ 47 | chmod 600 /home/ice/.ssh/config 48 | 49 | 50 | #запустить инсталл зависимостей 51 | RUN add-apt-repository ppa:chris-lea/node.js && \ 52 | apt-get update && \ 53 | apt-get -y install nodejs && \ 54 | apt-get -y install cmake git build-essential tmux g++ gcc libboost-all-dev wget 55 | 56 | #сменим права на локаллибы 57 | RUN chown ice /usr/local/lib && \ 58 | chown ice /usr/local/include 59 | 60 | # если мы не ставим пакет man-db, то можно убить все /usr/share/man/* тк их все равно нечем читать 61 | # сейчас стираем только переводы манов 62 | RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/man/?? /usr/share/man/??_* /usr/share/man/??.* 63 | -------------------------------------------------------------------------------- /bash_profile: -------------------------------------------------------------------------------- 1 | #загрузим юзеру ice переменные окружения при логине чз ssh 2 | source /etc/container_environment.sh 3 | -------------------------------------------------------------------------------- /boot2docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM boot2docker/boot2docker 2 | 3 | ADD automount-shares /tmp/automount-shares 4 | 5 | RUN rm $ROOTFS/etc/rc.d/automount-shares && \ 6 | cp /tmp/automount-shares $ROOTFS/etc/rc.d/automount-shares 7 | 8 | RUN /make_iso.sh 9 | 10 | CMD ["cat", "boot2docker.iso"] 11 | -------------------------------------------------------------------------------- /boot2docker/automount-shares.tpl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | #mount -o nolock 192.168.59.3:/Users 5 | while ! ip addr | grep 192.168.59 > /dev/null; do sleep 1; done 6 | 7 | HOST_VBOX_IP={IP} 8 | 9 | mountOptions='defaults' 10 | if grep -q '^docker:' /etc/passwd; then 11 | mountOptions="${mountOptions},uid=$(id -u docker),gid=$(id -g docker)" 12 | fi 13 | 14 | 15 | # try mounting "$name" (which defaults to "$dir") at "$dir", 16 | # but quietly clean up empty directories if it fails 17 | try_mount_share() { 18 | dir="$1" 19 | name="${2:-$dir}" 20 | 21 | echo $dir "***" $name 22 | mkdir -p "$dir" 23 | if ! mount -o nolock "$HOST_VBOX_IP":"$name" "$dir"; then 24 | rmdir "$dir" 2>/dev/null || true 25 | while [ "$(dirname "$dir")" != "$dir" ]; do 26 | dir="$(dirname "$dir")" 27 | rmdir "$dir" 2>/dev/null || break 28 | done 29 | 30 | return 1 31 | fi 32 | 33 | return 0 34 | } 35 | 36 | # bfirsh gets all the credit for this hacky workaround :) 37 | try_mount_share /Users 'Users' \ 38 | || try_mount_share /Users \ 39 | || try_mount_share /c/Users 'c/Users' \ 40 | || try_mount_share /c/Users \ 41 | || try_mount_share /c/Users 'c:/Users' \ 42 | || true 43 | -------------------------------------------------------------------------------- /boot2docker/build_iso.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | docker pull boot2docker/boot2docker 5 | 6 | cat automount-shares.tpl | sed -E 's/{IP}/'`ifconfig vboxnet0 | tail -1 | awk '{print $2}'`'/1' > automount-shares 7 | chmod 777 automount-shares 8 | 9 | docker build --no-cache=true -t my-boot2docker-img . 10 | 11 | docker run --rm my-boot2docker-img > boot2docker.iso 12 | 13 | rm automount-shares 14 | -------------------------------------------------------------------------------- /id_rsa.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCWsPYYTGTV78xyEtEi273oT7bO5VtQ6N+Q/M+Ojr7d0TSAQb556o7nfGL+GrWhbXdm/kWzRolvGzz0Je4VSGKsUG4aJ48lUHyUXk43p+2f1smL+SmTm9O4pV1YKg8nVBuAG0Scs1fDTs+9YWwC2p/gz+UmWqZ08BkoRKsIZpVtezmLdg12/iIqQ5H8BC/exjpH2InnsM549yDQO5WZfZxyaFNZIWpRIGqTyEH7rfsWeW+FQlZWaStesZXrknopiHr9gEGvCqNeN/QNb+2Nk4GEVxzHkoOYV49qdCaTfeCElfg3iHWKT2vcfGabDD75e5qj+8dBBo9sck9RsTmJZZfJ0zZ+rPyvvALHP/ZtbEYPCWiasm6uhSqmSyYYMo18nN5pq39/IluAYFpVOXZcx21Ni+BDPM+TnX2gNDZwZ12RJT4wdv6sBueunkQJTUAiGX6kqWpT84ZRFXDSMZIUMwnoLG3POYjx6XqPulKdi3A8h3TF14QioaN0azh/5PaNkKvNawnd8C83/YvYjaNaeLbh1iwJx4h5y1y9FqB5NLFJA4kTpvLNjSh2dp99PlmlKW6tEcagpdKJNFIyoQF9tmqTYbNK1vrJoOV5sL6MU/R4XejOUhnlYDnfZDggO53qpgBmUryREGuZKvy7+amNMgnCSgkjZxSBBnfTC5v89hNyCQ== ice@ice-laptop 2 | -------------------------------------------------------------------------------- /react/proposals.md: -------------------------------------------------------------------------------- 1 | Some things I can propose how to write components and make 2 | its easy to move `to-from` meteor in the future and now. 3 | 4 | 1) Read [this article from Dan Abramov](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0) 5 | (*using this ideas I've moved my projects from flummox to redux in hours, not days.*) 6 | 7 | This code https://github.com/plentiful/jobs/blob/master/app/client/components/job-table.cjsx is not reusable it's `smart` and `dumb`. 8 | In MVC approach you can think about `smart` components as like about 'controllers`. (React is not MVC but it's easy to think about if you've used MVC) 9 | 10 | Have a look at any component in my public project. 11 | [smart component example](https://github.com/istarkov/google-map-react-examples/blob/master/web/flux/components/examples/x_main/main_map_page.jsx) 12 | All this component do, is connect data (and subscribe to data changes) via `Connector` component to my `dumb` components. 13 | 14 | And if in the future I need to change stores to minimongo storage, 15 | all i need is to rewrite only `Connector` component and it's props, nothing else. 16 | 17 | 2) **Mixins are dead** - it's true, so don't use mixins for modern react code. 18 | https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750 19 | 20 | If you are using mixins now - your code is already old. 21 | 22 | But using `hoc` ideas we can simply rewrite this 23 | https://github.com/plentiful/jobs/blob/10dd0083383694f485d5f8c8e8c141f6ba425349/app/client/lib/react-factories.coffee and this 24 | ``` 25 | startMeteorSubscriptions: -> Meteor.subscribe 'JobTable' 26 | getMeteorState: -> jobs: Jobs.findAndSort().fetch() 27 | ``` 28 | to simple `Connector` like component with minimongo subscriptions and other stuff. 29 | 30 | But IMHO there is more easy way (at first sight), all we need is to reuse [Redux](https://github.com/gaearon/redux) framework (it's really great). 31 | 32 | I don't know Meteor much, but it looks like we can move this `startMeteorSubscriptions` to Redux action (with support of Redux middleware which will call store update `onDataChange`), and move `getMeteorState` in the same middleware. 33 | * unified action will look like `subscribe('Players', players => Players.find().fetch())` 34 | * imho unified actions is not a good way so just `subscribePlayers()` 35 | * action code will look like `subscribePlayers = () => ({type: MONGO_SUBSCRIPTION, table: 'players', fetch: players => Players.find().fetch()})` or more simple 36 | * the same is for updates etc - is just a Flux actions 37 | * the best is to create HOC over redux Connector with support of `subscribe` `unsubscribe` over Meteor subscriptions - so we can reuse all the code as we have or not Meteor at all. 38 | 39 | 3) It looks like there is no need in server rendering at all for `admin like` apps, 40 | so why not just to make meteor renders only simple html page with scripts generated with webpack. 41 | We get modern build system - `webpack`, hot reloading etc... 42 | And it looks like that next react versions will support Relay - and all data Meteor features become useless. (*IMHO*) 43 | 44 | 4) Why Redux - IMHO (I know and write on a lot amount of Flux frameworks) it's the best, it allows to create any available Flux framework with it, it's great and it's the child of two greatest react programmers - @aclark (flummox creator) and @gaearon (Dan Abramov - hot reload creator). 45 | 46 | 5) https://github.com/plentiful/jobs/blob/master/app/client/pages/edit-job.cjsx real fuck in render - 47 | ``` 48 | render: -> 49 | div {}, 50 | c JobHeading, id: @props.params.id 51 | JobForm job: @state.job 52 | ``` 53 | why to call `CreateElement` for `JobHeading` and not for `JobForm` IMHO it's an anti-patterb (я бы убивал за такой код (Шучу. Ваня) :-) ) 54 | Why to differntiate factory objects and class objects. This what i mean https://gist.github.com/sebmarkbage/fcb1b6ab493b0c77d589 55 | 56 | 6) CoffeeScript is a nowhere way (it looks good one year ago, but now :-( ) - for now Coffee looks like a dead language, one of the way to make your controls great is to publush them in open source world, is your need that almost nobody understand your language? I know that you think about tests - no tests gives you that can give a real user code review. 57 | (and tech is fast today - one year ago coffee was a real good choice, but not today) 58 | for example render function above in modern js looks like 59 | ```javascript 60 | render: () => 61 |
62 | 63 | 64 |
65 | ``` 66 | don't like `this` use spread 67 | ```javascript 68 | const {id} = this.props.params; 69 | ``` 70 | This code is more readable than cofee version - for almost any developer. 71 | (*for me this comma sign in Coffee "c JobHeading`,` id: @props.params.id" kills all 72 | 73 | As example can you explain in one fast sentence why this 74 | ``` 75 | div {}, 76 | c JobHeading, id: @props.params.id 77 | JobForm job: @state.job 78 | ``` 79 | is normal coffee code and 80 | this 81 | ``` 82 | div, 83 | c JobHeading, id: @props.params.id 84 | JobForm job: @state.job 85 | ``` 86 | is not :-) 87 | 88 | 7) React Meteor projects are also dead now - the most popular version supports React v0.13.0 (March 10, 2015), for example in my real work I never use projects like this. React and JS are so fast now - can you wait so long for observables support and many other features. 89 | -------------------------------------------------------------------------------- /react/readme.md: -------------------------------------------------------------------------------- 1 | #Angular vs React 2 | Проект начинался как чисто angularjs проект, потом переехал на смесь angularjs + ractive, потом переехал на чистый flux + react + immutablejs 3 | 4 | Тут кратко почему: 5 | ##Angular 6 | _я считаю angular отличной штукой и то что ниже меня напрягает, но какие то вещи я как писал так и буду писать на angular_ 7 | 8 | ####Бонусы 9 | * Готовый комбайн практически для любых сайтов, отличный framework со своей идеологией. 10 | * С введением es6 повсеместно, избавится от кучи своих анусов. 11 | * Имеет огромное сообщество и быстро развивается 12 | 13 | ####Анусы 14 | * angular фактически не предназначен для отрисовки сотен объектов, начиная с пары тысяч биндингов он ощутимо подтормаживает 15 | * angular не предназначен для рендеринга на сервере 16 | * angular порой неинтуитивен особенно это заметно когда объекты "отвязаны" от основного digest цикла (геморои начиная от promise до отрисовки) 17 | * ангуляр требует кучи допонительных действий даже если нужна простейшая либа - ее надо обернуть сервисом что то вроде 18 | ```javascript 19 | angular.module('services.algorithms', []). 20 | factory('algorithms', [function() { /*тут код*/ }]); 21 | ``` 22 | эту либу надо добавить в зависимости модуля, и тп 23 | * ошибки генерируемы ангуляром в случае косяков порой почти неуловимы, особенно когда они вслывают только на uglify коде 24 | * ангуляр требует почти постоянного жилья в документации по любым мало мальски не стандартным вопросам 25 | * механизм наследования scope контроллерами хорош ровно до того момента когда надо перенести подкомпоненту 26 | * порог вхождения в angular достаточно высок в плане количества времени затраченного на обучение - этому не способствуют как наличие кучи базовых сущностей - controller, directive, module, provider, service, compile ... 27 | так и куча особенностей работы с этим кодом 28 | - описание как создавать директиву и варианты ее параметров занимает множество страниц, все эти link, compile шаги, transcludeб, наследовние scope и множество чего еще; 29 | - 4 (или больше) вариантов как создать сервис; 30 | - resolve на роутинге, различные варианты роутов и тп 31 | * по сути требует изучения нового языка ng-repeat ng-if и прочие директивы 32 | * идеалогия писать логику отрисовки используя атрибуты html (см пред пункт) меня напрягает 33 | * из за обратной совместимости которую разработчики стараются не брякать имеет множество лишнего кода, который разрабы не убирают веруя что кто-то закладывается на этот код. 34 | * полное отсутствие инструментов позволяющих ускорить digest цикл например в случае использования immutable структур (все сравнения объектов вести на уровне byRef т.е. очень быстрого === ) 35 | 36 | --- 37 | 38 | Отличие как ractive так и react описанных ниже в том что они просто движки для отрисовки - и не имеют всех фич ангуляра типа $resource $route и тп. 39 | Оба используют для отрисовки идею virtual dom - т.е биндинги строятся по модели сравнения некоего виртуального кода до и после отрисовки - где по результатам сравнения принимается решения вносить ли изменения в реальный DOM 40 | 41 | Но как ractive так и react отлично ложаться в идеалогию flux, позволяют сходу использовать browserify для билдов (require модель) 42 | 43 | ###Кратко бонусы broserify 44 | * require модель подключения модулей в сто раз интуитивно понятней и проще чем модель модулей-сервисов ангуляра; 45 | * в любой момент можно вывести дерево зависимостей проекта; 46 | * умеет делать partition кода см https://github.com/substack/browserify-handbook#partitioning 47 | * позволяет не думая писать код который аналогично будет исполняться как на nodejs так и на клиенте - что для серверной отрисовки вообще незаменимо; 48 | * просты подключения трансформаций кода и тп - пример JSX модули facebook. 49 | * есть подобие с++ #ifdef и тп - что позволяет писать например dev версию кода и release в одном месте 50 | 51 | --- 52 | 53 | ##Ractive 54 | ####Бонусы 55 | * Достаточно низкий порог вхождения; 56 | * Использует для отрисовки разновидность mustache template языка, что выносит логику отрисовки из тегов html, и в силу крайней простоты mustache фактически не дает реализовывать всю логику отрисовки на стороне html _(вобщем это что промежуточное в подходе angular и react которые с моей точки зрения являются крайностями в подходе к отрисовке)_; 57 | * Самый большой бонус mustache что его разновидности известны либо понятны верстке - это один из самых простых шаблоных языков; 58 | * Вот вот получит нормальный серверный рендеринг _(тот что есть глюковат и требует полного reflow на клиенте)_; 59 | * То что это только движок для рендеринга позволяет использовать кучу хорошего opensource от нормальных promise до любого роутинга; 60 | * Нормально контачит с jquery кодом 61 | * Все сущности интуитивно понятны - template, component, decorator, partial. 62 | * Быстрая отрисовка 63 | 64 | ####Анусы 65 | * Вот вот получит нормальный серверный рендеринг - "вот воту" уже год; 66 | * Отстутствуют инструменты позволяющие ускорить сравнения внутри virtual dom; 67 | * Сообщество пока небольшое но быстро растущее; 68 | * Есть ряд глюков в отрисовке svg; 69 | * Нестабилен в плане будущих изменений api и тп - так как очень молод - с другой стороны api очень маленькое и это не страшно. 70 | 71 | --- 72 | 73 | ##React 74 | 75 | ####Бонусы 76 | * Очень низкий порог вхождения - имеет две сущности Element и Component, но при этом Component всегда является типом (базовым классом) Element - т.е. по сути сущность одна _(просто Element может не иметь component своим типом, поэтому тут сложно сказать одна или две сущности)_; 77 | * Уже отлично работающий серверный рендеринг; 78 | * Быстрая отрисовка, реально быстр особенно если использовать immutable типы и PureRenderMixin (это как работает closure om) 79 | * То что это только движок для рендеринга позволяет использовать кучу хорошего opensource от нормальных promise до любого роутинга; 80 | * Нормально контачит с jquery кодом; 81 | * Позволяет контролировать отрисовку на очень низком уровне см. closure om - т.е использовать immutable типы и вести быстрое сравнение 82 | _(immutable типы позволяют решать такую проблему javascript как недопущение абы кому менять объекты (read only доступ к объектам))_ 83 | И это очень важно: если глянуть как __большие дядьки__ пишут javascript код, то там все пропертя и объекты не подразумевающие изменений вплоть до того что замораживаются Object.freeze в девелоперских версиях кода (да да код фигачат в двух версиях - DEV версия и обычная) 84 | 85 | * Имеет за собой контору facebook - тут в отличии от angularjs который только проект сотрудников google, react это то на чем работает facebook. 86 | * Вообще не позволяет логики отрисовки на уровне html (всё на javascript) _(без JSX - разновидность очень маленького куска javascript этот крайний подход был бы скорее анусом - но в варианте с JSX это полубонус)_ 87 | * browserify наше все - построен на нем 88 | * Имеет четкую идеологию как его использовать - flux (если убрать весь трындеж facebook то основной бонус идеологии это правильное построение зависимостей require, и возможность удобно дробить код на мелкие независимые переюзабельные кусочки) 89 | 90 | 91 | ####Анусы 92 | * Есть ряд глюков в отрисовке svg (но они легко обходятся и скоро уйдут); 93 | * Крайне нестабилен в изменении API - но так как API почти нет - то это не страшно; _(правда в последнем обновлении потребовали сменить стиль именования компонет - на CamelCase для меня это было много тупых и однообразных правок)_ 94 | * JSX хоть и очень круто с точки зрения программера _(ещеб вся логика отрисовки теперь в javascript)_ - нифига не крут с точки зрения верстальщика 95 | 96 | --- 97 | #Выводы 98 | 99 | * По мне вот эти пункты __"Быстрая отрисовка"__, __"Уже отлично работающий серверный рендеринг;"__ кроют все остальные. 100 | * до кучи комбайны типа angularjs противоречат идеологии - делай одну вещь - делай ее хорошо, есть куча проектов где роутинги и тп сделаны лучше чем в ангуляре. 101 | 102 | ####Поэтому я выбрал react. 103 | 104 | (c) Иван Старков. 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ###Введение 2 | * Для начала ставим себе сам докер, подробности тут https://docs.docker.com/installation/mac/ 3 | * там же читаем что такое докер https://docs.docker.com/introduction/understanding-docker/ 4 | если лень читать, то docker контейнеры можно рассматривать как stateless виртуальные машины с мгновенным стартом, а сам docker это удобная среда для настройки, деплоя и управления контейнерами *(пока она очень удобна для работы с неколькими контейнерами в рамках одной машины, но в след. версиях уже будет удобна и в рамках кластера)* 5 | * если ставим на Linux то не забываем добавить своего юзера в группу docker 6 | ```sh 7 | sudo groupadd docker 8 | sudo gpasswd -a ${USER} docker 9 | sudo service docker restart 10 | ``` 11 | * добавляем след команды в (`~/.profile` или если пользуете ssh без логин крыжика то сюда `~/.bash_profile` на линуксе, `~/.bash_profile` на маке) 12 | не забываем `source ~/.profile` после добавления 13 | ```sh 14 | #подсветка stderr 15 | errh()(set -o pipefail;"$@" 2>&1>&3|sed $'s,.*,\e[31m&\e[m,'>&2)3>&1 16 | #бывает у докера на osx слетает ip этой командой можно восстановить 17 | dreloadhost() 18 | { 19 | 20 | SYSTEM=`uname` 21 | [ "$SYSTEM" = "Darwin" ] && export DOCKER_HOST="tcp://`boot2docker ip 2>&1 | sed -n 2,2p | awk -F' ' '{print $9}'`:2376" 22 | [ "$SYSTEM" = "Darwin" ] && export DOCKER_CERT_PATH=/Users/ice/.boot2docker/certs/boot2docker-vm 23 | [ "$SYSTEM" = "Darwin" ] && export DOCKER_TLS_VERIFY=1 24 | } 25 | dreloadhost 26 | #докер убить всех dkill -a 27 | dkill () 28 | { 29 | while : 30 | do 31 | case $1 in 32 | -a | --all) 33 | [ "$(docker ps -a -q)" ] && docker rm -f $(docker ps -a -q) 34 | shift 1 35 | ;; 36 | 37 | *) # no more options. Stop while loop 38 | [ "$1" ] && docker rm -f "$1" 39 | break 40 | ;; 41 | esac 42 | done 43 | [ "$(docker images | grep "^" | awk "{print $3}")" ] && docker rmi $(docker images | grep "^" | awk "{print $3}") 44 | } 45 | #приконнектица к контейнеру по ssh {port} 46 | dssh () 47 | { 48 | ssh -p $1 ice@`boot2docker ip 2>&1 | sed -n 2,2p | awk -F' ' '{print $9}'` 49 | } 50 | alias dps="docker ps" 51 | #утилитка для макоси для легкой установки nsenter 52 | denter() { 53 | CONTAINER=$1 54 | shift 1 55 | docker exec -it "$CONTAINER" su - ice -c 'script -q /dev/null' 56 | } 57 | ``` 58 | 59 | * после перезапустить shell (закрыть терминал открыть терминал) 60 | 61 | ####Почему docker нужен (основное): 62 | * Любой код что мы пишем требует какого то окружения (переменные среды дополнительные сервисы, библиотеки и т.п.), окружение среды у всех разное, что приводит к ошибкам на деплое *(например код работающий на маке отказывается запускаться в облаке google без дополнительных танцев)* 63 | * Многие библиотеки и сервисы на OSX ведут себя отлично от Linux, до кучи OSX не очень posix система что приводит к гемороям даже для простых bash команд - отличия в sed в awk и куче всего, аналогично различия в системных вызовах на c++ и тп. 64 | * Есть геморой по подключению, даже ненадолго, девелопера в чужой проект *(например настройка моего окружения по опыту у разработчиков занимает сутки - двое)*, аналогично я легко и быстро могу поправить чужой код на python или ruby если мне при этом не надо читать кучу док про pip gem версионность и тп. *(недавний опыт с питоном показал, что чтоб просто поправить три линии кода пришлось ставить питон - понимать чем питон 2 отличается от питон 3 и снова ставить питон, потом ставить pip узнавать команды pip и тп - это куча времени)* 65 | * Чем больше людей в проектах тем больше вероятность что окружение одного проекта начнет конфликтовать с окружением другого. 66 | * До кучи любимая нами ubuntu не везде стоит (в облаке гугл например нет образа ubuntu) те кто после убунту настраивали чистый debian или rhel или не дай бог oracle linux в курсе какого горя порой можно словить просто пытаясь разрулить установку даже привычных программ. 67 | * Dockerfile описывающий контейнер это легко читаемая последовательность об окружении системы, что немаловажно для администрирования 68 | 69 | --- 70 | 71 | ####Голый образ любой системы это не самая удобная вещь, поэтому я сразу напишу как сделать удобный рабочий контейнер 72 | * Всегда удобно взять за основу следующий image - 73 | "phusion/baseimage:" 74 | где версию глянуть тут https://github.com/phusion/baseimage-docker/blob/master/Changelog.md 75 | #####в чем бонусы этого image 76 | * построен на убунте 77 | * сразу настроен runit аналог supervisord, upstart и тп 78 | * настроены примочки как удобно просто копированием в Dockerfile добавлять процессы для старта 79 | * ENV переменные, сразу стоит ssh сервер (можно отключить) 80 | * Запущен cron (можно отключить) 81 | * Еще по мелочи - подробности про image тут https://github.com/phusion/baseimage-docker 82 | 83 | * Качаем версию себе в моем случае == 0.9.13 `docker pull phusion/baseimage:0.9.13` 84 | 85 | --- 86 | Под OSX есть неприятность - vboxsf очень медленная поэтому шарить файлы лучше под nfs (будет в разы быстрее а внешне разница ноль) 87 | 88 | Для удобного и быстрого шаринга файловой системы под OSX надо 89 | * Включить nfs на osx 90 | ```shell 91 | #включить nfs сервер 92 | sudo nfsd enable 93 | #отредактировать файл с папками для шаринга 94 | sudo vi /etc/exports 95 | # добавить /Users -mapall=YOUR_USER_NAME 96 | #проверить что нет ошибок 97 | sudo nfsd checkexports 98 | #проверить что папки подцпились 99 | sudo nfsd stop 100 | sudo nfsd start 101 | showmount -e 102 | ``` 103 | 104 | * Сбилдить правильный boot2docker образ 105 | ``` 106 | cd boot2docker 107 | ./build_iso.sh 108 | #перезаписать тот что есть 109 | boot2docker down 110 | cp boot2docker.iso ~/.boot2docker/boot2docker.iso 111 | boot2docker up 112 | ``` 113 | 114 | --- 115 | 116 | 117 | 118 | 119 | ###Поиграться сразу можно так 120 | ```sh 121 | docker run --rm -e "LANG=en_US.UTF-8" -e "LC_ALL=en_US.UTF-8" -t -i phusion/baseimage:0.9.13 /sbin/my_init -- bash -l 122 | ``` 123 | ####крыжики 124 | * -t выделить псевдо tty 125 | * -i не гасить stdin 126 | * -rm убить контейнер по завершении (без флага можно убитый контейнер закоммитить и тп) вобщем полезняк 127 | * bash -l === exec -l bash 128 | * -- выполнить команду используя my_init - идея что команда будет правильно стартанута чз runit с exec 129 | * -e "LANG=en_US.UTF-8" -e "LC_ALL=en_US.UTF-8" в контейнере по умолчанию херня полная с локалями поэтому пропишем ENV 130 | 131 | --- 132 | 133 | 134 | ###Теперь сбилдим контейнер на основе Dockerfile 135 | * отклонируем текущий проект себе 136 | ```bash 137 | cd projects 138 | git clone git@github.com:istarkov/docker.git 139 | cd docker 140 | ``` 141 | 142 | * **билдим базовый image** 143 | устанавливаем основные зависимости, создаем юзеров, 144 | прописываем ключи для ssh 145 | смотрим в Dockerfile там пошагово расписано что мы делаем 146 | ```bash 147 | #копируем в билд свой публичный ключ (нужен для ssh) 148 | cp ~/.ssh/id_rsa.pub id_rsa.pub 149 | #билдим базовый image 150 | docker build -t istarkov/base . 151 | ``` 152 | 153 | * создаем image основанный на базовом, что будет происходить смотрим в tmuxexample/Dockerfile 154 | устанавливаем глобальные зависимости проекта, компилим библиотеку, прописываем deplyment ключ проекта, клонируем проект (и тп.) 155 | ```bash 156 | docker build -t istarkov/tmuxexample tmuxexample 157 | ``` 158 | * или полный ребилд (он нужен например если произошли изменения во внешних файлах и тп) 159 | ```sh 160 | docker build --no-cache=true -t istarkov/tmuxexample tmuxexample 161 | ``` 162 | 163 | 164 | 165 | файлы Dockerfile хорошо откомментированы и легки для прочтения, поэтому подробности что и зачем они делают внутри 166 | ####Cтартуем 167 | * либо так - если чуем, что что то придется доставлять в контейнер и т.п. *(по хорошему у юзера ice созданного на предыдущем шаге не должно быть sudo)* поэтому контейнер будет запущен в интерактивном режиме c запущенным bash 168 | ```bash 169 | docker run --name ice --rm -t -i -p 3222:22 -e HOSTNAME=tmuxexample istarkov/tmuxexample /sbin/my_init -- bash -l 170 | ``` 171 | * или так - в демон режиме 172 | ```bash 173 | docker run --name ice -d -t -p 3222:22 -e HOSTNAME=tmuxexample istarkov/tmuxexample 174 | ``` 175 | * *новые крыжики* 176 | * -p 3222:22 замапить порт 3222 на хост машине на порт 22 докера 177 | 178 | --- 179 | 180 | --- 181 | 182 | ####Начинаем играть с контейнером 183 | * На маке по ssh к полученному контейнеру можем сконнектится так `dssh 3222` 184 | 185 | * На линуксе так `ssh -p 3222 ice@linux_machine_ip` 186 | * **На сам докер на линуксе и на маке лучше всего не заходить по ssh** (_иногда надо_) а использовать прекрасную утилитку nsenter 187 | Если вы прописали alias в .bash_profile, просто запустить `denter {container-id}` и он установится 188 | Если пользуете tmux то не используйте родной docker-enter а пользуйте мой alias, родной не дает tty откуда все интерактивные утилиты работать не будут. (_точнее tty то дает но не в контексте докера, а использует tty хоста, имеем редкий случай shell interactive а tty нет, isatty() возврщает true, и при этом /dev/pts/ пустой_) 189 | * _ssh нужен например когда нет желания или возможности дать права кому либо на хост сервер_ 190 | * _по хорошему не нужен и является дырой в безопасности и лишним гемороем_ 191 | * Убить все контейнеры `dkill -a`, убить конкретный `dkill {начало_id}` или `dkill {name}` (_бывают ситуации когда контейнеры несмотря на крыжик --rm не умирают после закрытия поэтому dkill ваш друг_) 192 | * Посмотреть какие контейнеры есть в системе dps -a 193 | * Если вы зашли по nsenter то вся сессия логируеца в ~/typescript (см script команда) - посмотреть можно когда юзер отлогинился 194 | * [Почему вам не нужен sshd в Docker-контейнере] (http://habrahabr.ru/company/infopulse/blog/237737/) 195 | 196 | 197 | ####Различные заморочки с правами 198 | * **Шаринг хост файловой системы** 199 | на контейнере что мы создали у юзера ice uid==1000 (обычно первый юзер получает такой) 200 | отсюда он прекрасно будет и сможет работать с папками разшаренными ему из под хост системы у которых owner тоже с uid=1000 201 | вобщем запоминаем прекрасные команды 202 | ```sh 203 | #прибить все процессы юзера 204 | pkill -u {user} 205 | #сменить uid у юзера 206 | sudo usermod -u 1000 {user} 207 | ``` 208 | (_в случае osx шара на виртуальной linux машине привязана к docker пользователю с uid=1000 поэтому нам надо на серверах чтобы окружение было одинаковым ставить uid равный 1000 юзеру от которого будем пускать контейнер_) 209 | 210 | * __Запуск из под другого пользователя__ если нам надо будет пускать контейнеры например из psql или с вебсервера - то есть в ситуациях когда юзер от имени которого надо стартануть контейнер не дефолтный user c uid=1000 тогда надо будет прописать в sudoers разрешение юзеру запускать любые команды от имени другого юзера 211 | ```sh 212 | visudo 213 | # добавить строчку psql ALL=(ice) NOPASSWD:ALL 214 | # означает разрешить юзеру psql выполнять любые команды от имени ice 215 | ``` 216 | и затем вызывать команды либо используя 217 | ```sh 218 | sudo -u ice COMMAND [args...] 219 | ``` 220 | либо использовать утилитку setuser (https://raw.githubusercontent.com/phusion/baseimage-docker/master/image/bin/setuser) которая помимо юзера настроит еще и некоторые переменные среды 221 | ```sh 222 | ../utils/setuser ice COMMAND [args...] 223 | ``` 224 | 225 | 226 | ####Ошарить порты на мак машину 227 | ```sh 228 | for i in {3010..3100}; do 229 | VBoxManage modifyvm "boot2docker-vm" --natpf1 "tcp-port$i,tcp,,$i,,$i"; 230 | VBoxManage modifyvm "boot2docker-vm" --natpf1 "udp-port$i,udp,,$i,,$i"; 231 | done 232 | ``` 233 | 234 | ####Логи из контейнера (_два варианта_) 235 | * первый универсальный (_перенаправлять tail -F логфайл в stdout_) тут см пример https://github.com/phusion/passenger-docker/tree/master/image/runit _nginx, nginx-log-forwarder_ 236 | * конкретно для nginx этого делать ненадо у него есть крыжики выводить логи в stdout тут http://blog.froese.org/2014/05/15/docker-logspout-and-nginx/ 237 | * собирать логи с контейнеров на хосте лучше так https://github.com/progrium/logspout (использует недавно выкаченное api для контейнеров и сам пашет в контейнере) 238 | 239 | ####Ручные Полезняки: 240 | * стереть image так 241 | ```sh 242 | docker rmi sentimeta/python_all_scikit 243 | ``` 244 | 245 | * убить все не сбилженые контейнеры и имажи 246 | ```sh 247 | docker rm -f $(docker ps -a -q) 248 | docker rm -f $(docker ps -a -q --filter 'exited=0') 249 | docker rmi $(docker images | grep "^" | awk "{print $3}") 250 | ``` 251 | * посмотреть какие есть сбилженые image 252 | ```sh 253 | docker images 254 | ``` 255 | * остальные команды читать тут https://docs.docker.com/userguide/ 256 | * как настроить image coreos чтобы сразу на приватное репо без пароля https://coreos.com/docs/enterprise-registry/configure-machines/ 257 | 258 | --- 259 | 260 | ####Косяки 261 | * надо очень аккуратно с head командами https://github.com/docker/docker/issues/8027 262 | * при работе с большими файлами gnu parallel не чует что место на диске кончилось и гонит лажу, 263 | если очень надо с ними работать именно на маке - то надо увеличить размер диска виртуальной машины 264 | https://docs.docker.com/articles/b2d_volume_resize/ 265 | 266 | ####Правильный деплой 267 | ```sh 268 | 1>/dev/null git fetch --all && 1>/dev/null git checkout --force origin/master 269 | ``` 270 | 271 | ####Как работать с приватными репо (зависит от бюджета) 272 | * вот эти самые нормуль https://quay.io/tour/organizations 273 | 274 | 275 | ###Офигенная неприяность докера маленький dev/shm размер и геморой с шарингом файловой системы контейнера в хост систему на OSX (Mac) 276 | *Что не дает выделять большие непрерывные куски shared памяти а именно больше 65мб что для многих задач расчета неприемлимо* 277 | *А шаринг файловой системы нужен как для размещения db файлов на хост системе (лучше рассматривать контейнеры как stateless объекты) так и для удобной разработки - когда правки кода сразу видны в контейнере* 278 | 279 | ####Как с этим боремся - правим код докера, и код boot2docker если у вас apple мак 280 | * __Вариант 1__ 281 | Качаем два уже подготовленных мной файла https://drive.google.com/folderview?id=0B-jWb9pIDkx-NS05TFdwZVNGQm8&usp=sharing 282 | подменяем ./boot2docker/boot2docker.iso на скачанный boot2docker.iso 283 | Шарим фолдер на макоси на виртуалку - чтобы mount volume опция докера работала на макоси также как и на linux 284 | ```sh 285 | VBoxManage sharedfolder add boot2docker-vm -name home -hostpath /Users 286 | ``` 287 | 288 | копируем на linux сервера файл docker-1.2.0-dev заходим по ssh и выполняем команду (подменяем установленный докер сервис своим) 289 | ```sh 290 | sudo service docker stop ; sudo cp $(which docker) $(which docker)_ ; sudo cp docker-1.2.0-dev $(which docker);sudo service docker 291 | ``` 292 | 293 | 294 | * **Вариант 2** 295 | __билдим docker и boot2docker сами__ 296 | Запускаем linux (*под маком с билдом докера лучше не связываться*) не забываем добавить своего юзера в группу docker 297 | ```sh 298 | sudo groupadd docker 299 | sudo gpasswd -a ${USER} docker 300 | sudo service docker restart 301 | ``` 302 | * читаем и настраиваем https://docs.docker.com/contributing/devenvironment/ 303 | * в коде vendor/src/github.com/docker/libcontainer/mount/init.go правим размер shm на достойный 304 | ```go 305 | {source: "shm", path: filepath.Join(rootfs, "dev", "shm"), device: "tmpfs", flags: defaultMountFlags, data: label.FormatMountLabel("mode=1777,size=ОЧЕНЬМАЛЕНЬКИЙнаОЧЕНЬБОЛЬШОЙ", mountLabel)} 306 | ``` 307 | 308 | * потом билдим докер (см. ссылку) генерим бинарник и выполняем 309 | ```sh 310 | sudo service docker stop ; sudo cp $(which docker) $(which docker)_ ; sudo cp ./bundles/1.2.0-dev/binary/docker-1.2.0-dev $(which docker);sudo service docker start 311 | ``` 312 | 313 | дальше надо этот бинарник заюзать для osx, 314 | для этого нам надо перебилдить boot2docker.iso или попросить его у меня. 315 | 316 | ###Создаем build для boot2docker 317 | *(это если в предыдущем пункте был выбран вариант 2)* 318 | 319 | * Запускаем linux (*под маком с билдом тоже лучше не связываться*) 320 | * отпулим себе базовый контейнер билда iso 321 | ```sh 322 | docker pull boot2docker/boot2docker 323 | ``` 324 | * откопируем новый docker себе в папку с boot2docker 325 | ```sh 326 | cp /home/ice/docker_test/docker_src/docker/bundles/1.2.0-dev/binary/docker-1.2.0-dev docker-1.2.0-dev 327 | ``` 328 | * создаем докерфайл 329 | ```sh 330 | FROM boot2docker/boot2docker 331 | COPY docker-1.2.0-dev $ROOTFS/usr/local/bin/docker 332 | RUN chmod +x $ROOTFS/usr/local/bin/docker 333 | #тут код для установки guest additions на виртуальную машину который копипастим отсюда https://gist.github.com/mattes/2d0ffd027cb16571895c 334 | RUN /make_iso.sh 335 | CMD ["cat", "boot2docker.iso"] 336 | ``` 337 | * билдим контейнер который в процесе билда создаст образ 338 | ```sh 339 | sudo docker build -t istarkov/boot2docker . 340 | ``` 341 | * выводим результат себе из контейнера 342 | ```sh 343 | sudo docker run --rm istarkov/boot2docker > boot2docker.iso 344 | ``` 345 | * гасим докер если запущен 346 | ```sh 347 | boot2docker down 348 | ``` 349 | * копируем сбилженое iso к себе 350 | ```sh 351 | rsync -e ssh -avz --progress ice@turk:~/build_boot_2_docker/docker/boot2docker/boot2docker.iso ~/.boot2docker/boot2docker.iso 352 | ``` 353 | * Шарим фолдер на макоси на виртуалку - чтобы mount volume опция докера работала на макоси также как и на linux 354 | ```sh 355 | VBoxManage sharedfolder add boot2docker-vm -name home -hostpath /Users 356 | ``` 357 | * Апаем boot2docker взад и проверяем что все замапилось нормально 358 | ```sh 359 | boot2docker up 360 | #не ленимся прописать export DOCKER_HOST=tcp://смотри вывод boot2docker up:2375 361 | boot2docker ssh 362 | cd /Users 363 | #если все нормально то в папке /Users должны быть директории макоси /Users 364 | exit 365 | ``` 366 | 367 | 368 | 369 | 370 | -------------------------------------------------------------------------------- /ssh_config: -------------------------------------------------------------------------------- 1 | Host bitbucket.org 2 | StrictHostKeyChecking no 3 | -------------------------------------------------------------------------------- /tmuxexample/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM istarkov/base 2 | 3 | #откопировать deployment key для bitbucket 4 | ADD id_deployment_key /home/ice/.ssh/id_rsa 5 | RUN chown ice /home/ice/.ssh/id_rsa && \ 6 | chmod 600 /home/ice/.ssh/id_rsa 7 | 8 | 9 | #зависимый код от репо - глобальные зависимости проекта 10 | RUN npm install -g node-gyp && \ 11 | npm install -g supervisor && \ 12 | npm install -g grunt-cli && \ 13 | chown ice -R /home/ice/.npm 14 | 15 | #сменим юзера на ice и дальше весь акшен от его имени 16 | USER ice 17 | 18 | #отклонировать репо дать ссылку на ран 19 | RUN cd /home/ice && \ 20 | git clone git@bitbucket.org:cybice/testn.git && \ 21 | ln -n -s /home/ice/testn/tmux_run /home/ice/runme 22 | 23 | #установим либу из сети 24 | RUN mkdir -p /home/ice/jansonn && \ 25 | cd /home/ice/jansonn && \ 26 | wget http://www.digip.org/jansson/releases/jansson-2.6.tar.gz && \ 27 | tar -zxvf jansson-2.6.tar.gz && \ 28 | cd jansson-2.6 && \ 29 | ./configure && \ 30 | make && \ 31 | make check && \ 32 | make install 33 | 34 | 35 | #вернем юзера на рут, запустим ldconfig ибо часть путей библиотек могла прописаться в /etc/ld.so.conf или /etc/ld.so.conf.d 36 | USER root 37 | RUN ldconfig 38 | 39 | # Clean APT if need. 40 | -------------------------------------------------------------------------------- /tmuxexample/id_deployment_key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpgIBAAKCAQEA7Y98p3nDtFD0nnNfCkTBSD0NkIn2KgAR3d2fpb1rhZRmLUjb 3 | 4TDJVFkutBMAQU92KFmyUtvHTorCpwFStx8qYaG6ERpxJqM4WHMEkrY9SA92Wimh 4 | TpVhnaDrpI9kr0TM0xAuozXwVAyaVR2vatsIgrWUJ5JDGVwCbXmv7RBc5XEdpAC+ 5 | faCKVRjbIApYDLeN4Lg1/spYNQ498gNsWu3VdMjUOHKXfqu/F0wpk5urdtav0eOZ 6 | gYkq5nToD+KZeaNxp1vDN1EvC6S+FvPodJg/ccIDAEI2iyMcc+iOVGT62zblnT+S 7 | IAnD7OTp6c2KcSy5H7yBJmlpvOiTWTd51Qp96wIDAQABAoIBAQCTTzmuJGx94QF/ 8 | S+1wUahFIk7KBTLXYomxuZ8oyGfnQlmF1Ts7zePaYR773Rh4Z0zOwqg4hz507si7 9 | hK+FDFdciUv3FR17JxVmi5QXYdhoWeY7DLuRHkKU21ekCKMXqCMW8l7pKCZqCBKf 10 | mzPOoBoL64r+as0e6ZY7yoyUBWSFhUgrATWXyYRbiv0PcNklUOtv27ULF4i70c5O 11 | HIeUO8HSuel46r1a3Fnwr+P6o45eOdVjntTrKM2cg1IQ87gldMR5ywMEATzGD8UK 12 | SmmYwGgtUGjL351Ck9iipT5AOLD/pP8O3iqznH7Vjhpk9F9ZCRavt+zwTIXe2hRo 13 | 3muGQw1ZAoGBAP6cx5EsPmCgryo7serh8VVhIvU3doaJhkQ6iObpGIVyEr8jKCJC 14 | IJQ/5ImnbqAzeLS6hPUot33jd8N2E9i3FRp5p4j3+RLOS/Oof/E0xYN5oOlkZ7CY 15 | eZPJXmR5dWTP4rfApByOISj8BVYc8fISRtsaDEuouN+zMi+1ddxQs9NdAoGBAO7a 16 | 6uJ83GnwYw9sg1v2ZQeA14xXPtSkIEFt4lY4RHvBtBWOg7lKhHjtmtWYnIlVce1T 17 | Bff71FxdfGloNsyLhNxEnjf/mwemw2nHpjD+nLLf7gLvg07CB8vW62UXb3ShWsbG 18 | APN6EHPFaHm7qxT0/xqy7f7MZ1ISblxQV1YQsonnAoGBANP0ddnvZ/oOqeNRkHoF 19 | H19BHtXeFwhGogRYajE36JbmcJ63SKjEPdTMH5dMT7aDQr/I6fggrifZXZDU0g69 20 | 0o6YqZRHQgyaufWb1u5YTPh3HzJLyFnlhIg3wSGJTuXefVEUyEmRNB+nNVYLgIpR 21 | FrU8yPGPAmAPD/9RY01FzX1tAoGBAJkBx8F6dr+ua+avfp5kgmeCE5IlOWyCDt+b 22 | Aoh01vnoJfJBLwR9Rcspeiwl7PDUuXxr2MD4oxrgEBh918zD+0IW+ruok6kdHMUg 23 | TcfI8pxrck6TG6xSAyiC7pv9nTo7OqlmoalWoj9nT/vbSkbMgraZtHeqfO1IPUYJ 24 | eUj6vUQ1AoGBAJi7KDUyTKHjeogFwso8LWtZMnFvlsehRBZCkOLKU2bo7Xl3/3RS 25 | w9GfiJpuuzpSnfG2MXIOZDvGoUujrKBw/0kmwwzbeAYsmAiTEEIrnC3f+3Gn8jg4 26 | ga1kThBfkMrxYLGgqSirpCRVCxFvBjU134hETz1Tha45aMCAHsu0xY3X 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tmuxexample/id_deployment_key.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDtj3ynecO0UPSec18KRMFIPQ2QifYqABHd3Z+lvWuFlGYtSNvhMMlUWS60EwBBT3YoWbJS28dOisKnAVK3HyphoboRGnEmozhYcwSStj1ID3ZaKaFOlWGdoOukj2SvRMzTEC6jNfBUDJpVHa9q2wiCtZQnkkMZXAJtea/tEFzlcR2kAL59oIpVGNsgClgMt43guDX+ylg1Dj3yA2xa7dV0yNQ4cpd+q78XTCmTm6t21q/R45mBiSrmdOgP4pl5o3GnW8M3US8LpL4W8+h0mD9xwgMAQjaLIxxz6I5UZPrbNuWdP5IgCcPs5OnpzYpxLLkfvIEmaWm86JNZN3nVCn3r istarkov@gmail.com 2 | -------------------------------------------------------------------------------- /watch.md: -------------------------------------------------------------------------------- 1 | ###Docker контейнеры для web-разработчика под OSX 2 | Всю свою текущую разработку, я веду используя docker контейнеры, и если под linux такой подход не вызывает никаких проблем, то под макосью некоторые моменты могут отнять невероятное количество сил и времени. 3 | 4 | Об одном из таких моментов я и хочу рассказать. 5 | 6 | В моем случае, разработка с иcпользованием docker выглядит так - на контейнере поднят весь необходимый мне софт. 7 | Папки с рабочим проектом смаплены с хост системы в контейнер. 8 | В контейнере для автобилда настроен либо [grunt] с [grunt-contrib-watch], либо [watchify], либо порой просто висит скриптик использующий [inotify-tools]. 9 | Дальше в случае веб разработки цикл простой - я правлю на Маке файл проекта, watch утилитки стартуют билд, livereload обновляет web страничку. 10 | 11 | Все бы хорошо - но первая возникающая при таком подходе проблема, это то что входящая в Virtualbox Guest Additions файловая система vboxsf невероятно медленная и вызывает целый ряд проблем: 12 | * Все watch утилитки начинают грузить систему процентов на 200 13 | * Даже небольшая сборка - например простая конкатенация файлов начинает занимать десятки секунд. 14 | 15 | И это неприемлимо. 16 | 17 | --- 18 | 19 | Быстрое гугление показало, что [nfs] работает в разы быстрее чем vboxfs. 20 | До кучи настроить [nfs] сервер под OSX быстро и легко. 21 | ```shell 22 | #включить nfs сервер 23 | sudo nfsd enable 24 | #отредактировать файл с папками для шаринга 25 | sudo vi /etc/exports 26 | # добавить папки которые надо сделать доступными например /Users/user/my_web_project -mapall=ice 27 | #проверить что нет ошибок 28 | sudo nfsd checkexports 29 | #проверить что папки подцпились 30 | showmount -e 31 | ``` 32 | 33 | Дальше надо передать в docker, ip адрес OSX хоста, чтобы можно было подцепить файловую систему 34 | ```shell 35 | #получить ip хоста висящего на интерфейсе virtual box 36 | HOST_IP=`ifconfig vboxnet0 | tail -1 | awk '{print $2}'` 37 | #передать в контейнер 38 | docker run --name smap -p 3080:3080 -e HOST_IP="$HOST_IP" -d -t sentimeta/node_scikit_image 39 | ``` 40 | В контейнере надо накатить [nfs] клиента и замаунтить нужные папки 41 | ```shell 42 | #накатить клиента 43 | sudo apt-get update 44 | sudo apt-get install nfs-common 45 | #замаунтить nfs osx папку 46 | sudo mount -o nolock "$HOST_IP":/Users/user/my_web_project ~/my_web_project 47 | ``` 48 | 49 | --- 50 | 51 | И действительно две проблемы уходит 52 | - загрузка процессора около ноля 53 | - билд теперь идет очень быстро 54 | 55 | Но появляется новая проблема - inotify события файловой системы [nfs] на которых сидят все watch утилитки, проходят, но с задержками по 10-20 секунд. 56 | И это неприемлимо. 57 | 58 | --- 59 | 60 | Поэтому было принято решение начать ловить inotify события на host машине и передавать информацию в docker контейнер. 61 | Для решения проблемы я использовал следующие утилитки 62 | - на стороне докера [netcat] 63 | - на стороне OSX [fswatch] и [curl] 64 | 65 | #####Сторона докера 66 | Вешаем http веб сервер на 3080 порт 67 | ```shell 68 | watch -n0 'printf "HTTP/1.1 200 OK\n\n$(date && touch /home/user/my_web_project/watchhelper.tmp)\n" | nc -l -p 3080 >/dev/null && date' 69 | ``` 70 | это самый __настоящий веб сервер на bash__ висящий на 3080 порту, 71 | на каждый запрос он выполняет команду date и touch файла watchhelper.tmp который надо положить вне исходников вашего проекта который надо добавить в watch. _ниже я поясню почему вне исходников проекта_ 72 | - touch команда "трогая" файл вызывает inotify событие приводяещее к сборке 73 | - date команда удобна для тестирования, ее вывод и есть ответ этого сервера 74 | 75 | Проверить что работает можно так: 76 | - На OSX получаем адрес boot2docker виртуальной машины - `boot2docker ip 2>&1 | sed -n 2,2p | awk -F' ' '{print $9}'` 77 | - Заходим в браузере по ip полученному предыдущей командой на порт 3080 78 | И ура - в браузере видим время, а в контейнере мгновенное срабатывание watch утилиток. 79 | 80 | 81 | #####Сторона OSX 82 | Устанавливаем fswatch 83 | `brew install fswatch` 84 | Запускаем 85 | ```shell 86 | fswatch-run /Users/user/my_web_project/src "curl http://`boot2docker ip 2>&1 | sed -n 2,2p | awk -F' ' '{print $9}'`:3080" 87 | ``` 88 | Теперь при изменении любого файла в папке /Users/user/my_web_project/src будет вызван поднятый в контейнере веб сервер, который "потрогает" файл, что в свою очередь вызовет билд. 89 | 90 | Файл watchhelper.tmp надо расположить вне исходников проекта по причине, что [nfs] все таки пропускает inotify события и лежащий в исходниках файл вызовет вечный цикл curl touch touch событий. 91 | 92 | --- 93 | 94 | Различные вопросы настройки докер контейнеров под макось я нерегулярно добавляю в проект на гитхабе [istarkov/docker] 95 | 96 | --- 97 | 98 | Если тема вызовет отклик - напишу еще несколько заслуживающих внимания вещей при использовании docker контейнеров при разработке на OSX. 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | [grunt]:http://gruntjs.com/ 140 | [grunt-contrib-watch]:https://github.com/gruntjs/grunt-contrib-watch 141 | [watchify]:https://github.com/substack/watchify 142 | [inotify-tools]:https://github.com/rvoicilas/inotify-tools 143 | [nfs]:http://en.wikipedia.org/wiki/Network_File_System 144 | [netcat]:http://en.wikipedia.org/wiki/Netcat 145 | [fswatch]:https://github.com/emcrisostomo/fswatch 146 | [curl]:http://curl.haxx.se/ 147 | [istarkov/docker]:https://github.com/istarkov/docker 148 | --------------------------------------------------------------------------------