├── .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 |
--------------------------------------------------------------------------------