{"id":281537,"date":"2016-11-25T11:50:03","date_gmt":"2016-11-25T08:50:03","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=281537"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=281537","title":{"rendered":"\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 Django \u0438\u0437 GitLab"},"content":{"rendered":"<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043e\u043f\u0438\u0448\u0443 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u0442\u0435\u043a\u0435 Django + uWSGI + PostgreSQL + Nginx \u0438\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0435 <a href=\"https:\/\/gitlab.com\">GitLab.com<\/a>. \u0418\u0437\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0435 \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c\u043e \u043a \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u043e\u0439 \u0438\u043d\u0441\u0442\u0430\u043b\u043b\u044f\u0446\u0438\u0438 GitLab. \u041f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044c \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442 \u043e\u043f\u044b\u0442\u043e\u043c \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 Django, \u0430 \u0442\u0430\u043a \u0436\u0435 \u043e\u043f\u044b\u0442\u043e\u043c \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f Linux-\u0441\u0438\u0441\u0442\u0435\u043c.<\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<p>\u0420\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"http:\/\/fabfile.org\">Fabric<\/a>, <a href=\"https:\/\/docker.io\">Docker<\/a> \u0438 <a href=\"https:\/\/docs.docker.com\/compose\">docker-compose<\/a>, \u0430 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c \u0435\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u0435\u0440\u0432\u0438\u0441 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u0439 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438, \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u0432 GitLab, \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <a href=\"https:\/\/about.gitlab.com\/gitlab-ci\">GitLab CI<\/a>.<\/p>\n<p>  <\/p>\n<h1 id=\"mehanizm-avtomaticheskogo-razvyortyvaniya\">\u041c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f<\/h1>\n<p>  <\/p>\n<p>\u0420\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p>  <\/p>\n<ol>\n<li>\u041f\u0440\u0438 push&#8217;e \u043d\u043e\u0432\u044b\u0445 \u043a\u043e\u043c\u043c\u0438\u0442\u043e\u0432 \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0431\u0443\u0434\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f GitLab CI.<\/li>\n<li>GitLab CI \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c Docker-\u043e\u0431\u0440\u0430\u0437 \u0441 \u0433\u043e\u0442\u043e\u0432\u044b\u043c \u043a \u0437\u0430\u043f\u0443\u0441\u043a\u0443 Django-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c.<\/li>\n<li>\u0417\u0430\u0442\u0435\u043c GitLab CI \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442 (<em>push<\/em>) \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0439 Docker-\u043e\u0431\u0440\u0430\u0437 \u0432 <a href=\"https:\/\/about.gitlab.com\/2016\/05\/23\/gitlab-container-registry\">GitLab container registry<\/a>. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0441\u0442\u0438 \u0432 registry \u0442\u0435 \u0436\u0435, \u0447\u0442\u043e \u0438 \u0443 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f, \u0442.\u0435. \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0445 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432 GitLab registry <strong>\u043e\u0442\u043a\u0440\u044b\u0442 \u0434\u043b\u044f \u0432\u0441\u0435\u0445<\/strong>.<\/li>\n<li>Gitlab CI \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442 \u044e\u043d\u0438\u0442-\u0442\u0435\u0441\u0442\u044b.<\/li>\n<li>\u0412 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u043a\u043e\u043c\u043c\u0438\u0442\u044b \u0438\u043b\u0438 merge request&#8217;\u044b \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043b\u0438\u0441\u044c \u0432 \u0433\u043b\u0430\u0432\u043d\u0443\u044e \u0432\u0435\u0442\u043a\u0443 (<code>master<\/code>), \u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0441\u0431\u043e\u0440\u043a\u0438 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f Gitlab CI \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Fabric \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0451\u0442 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0439 Docker-\u043e\u0431\u0440\u0430\u0437 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0441 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u043c \u043d\u0430\u043c\u0438 IP-\u0430\u0434\u0440\u0435\u0441\u043e\u043c.<\/li>\n<\/ol>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u2014 \u0437\u0430\u043a\u0440\u044b\u0442\u044b\u0435 \u043a\u043b\u044e\u0447\u0438, <code>SECRET_KEY<\/code> \u0434\u043b\u044f Django, \u0442\u043e\u043a\u0435\u043d\u044b \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0438 \u0442.\u0434. \u2014 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0442\u0435\u043a\u0441\u0442\u043e\u043c \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e \u043d\u0435 \u0441\u0442<em>\u043e<\/em>\u0438\u0442, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043b\u044f \u0438\u0445 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u043e\u043c <a href=\"https:\/\/docs.gitlab.com\/ce\/ci\/variables\/README.html#user-defined-variables-secure-variables\">GitLab Secret Variables<\/a>:<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/bd5\/a1c\/a89\/bd5a1ca898a24f8ca8499ace094f4d62.png\" alt=\"image\"\/><\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438 \u0442\u0430\u043a\u043e\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u0435 \u043a\u043e\u043d\u0444\u0438\u0434\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0442\u0435\u043a\u0441\u0442\u043e\u043c \u043b\u0438\u0448\u044c \u0432 \u0434\u0432\u0443\u0445 \u043c\u0435\u0441\u0442\u0430\u0445: \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 GitLab.com \u0438 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435. \u0412 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u043a\u043e\u043d\u0444\u0438\u0434\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f (\u0447\u0438\u0442\u0430\u0439: \u0431\u0443\u0434\u0443\u0442 \u0432\u0438\u0434\u043d\u044b \u043b\u044e\u0431\u043e\u043c\u0443, \u043a\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043d\u0430 \u043d\u0435\u0433\u043e \u0437\u0430\u0439\u0442\u0438 \u043f\u043e SSH).<\/p>\n<p>  <\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 \u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<ul>\n<li><code>DEPLOY_KEY<\/code> \u2014 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c SSH-\u043a\u043b\u044e\u0447\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0432\u0445\u043e\u0434\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440;<\/li>\n<li><code>DEPLOY_ADDR<\/code> \u2014 \u0435\u0433\u043e IP-\u0430\u0434\u0440\u0435\u0441;<\/li>\n<li><code>SECRET_KEY<\/code> \u2014 <a href=\"https:\/\/docs.djangoproject.com\/en\/dev\/ref\/settings\/#std:setting-SECRET_KEY\">\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f<\/a> \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 Django.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0432 \u0444\u0430\u0439\u043b\u0435 <code>settings.py<\/code> Django-\u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c <code>SECRET_KEY<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p>  <\/p>\n<pre><code>SECRET_KEY = os.getenv('SECRET_KEY') or sys.exit('SECRET_KEY environment variable is not set.')<\/code><\/pre>\n<p>  <\/p>\n<h1 id=\"shag-1-docker\">\u0428\u0430\u0433 1: Docker<\/h1>\n<p>  <\/p>\n<p>\u0412 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c <code>Dockerfile<\/code> \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Django \u0438 uWSGI \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043b\u0435\u0433\u043a\u043e\u0432\u0435\u0441\u043d\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u0430 <a href=\"https:\/\/hub.docker.com\/_\/alpine\">Alpine Linux<\/a>:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">web\/Dockerfile<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code>FROM python:3.5-alpine  RUN mkdir -p \/usr\/src\/app WORKDIR \/usr\/src\/app  RUN apk add --no-cache --virtual .build-deps gcc musl-dev linux-headers pkgconf \\     autoconf automake libtool make postgresql-dev postgresql-client openssl-dev &amp;&amp; \\     apk add postgresql-libs postgresql-client &amp;&amp; \\     # \u041f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u043d\u0435\u0443\u0434\u0430\u0447\u043d\u0443\u044e \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u044e uWSGI \u0432\u043d\u0443\u0442\u0440\u0438 Docker, \u0441\u043c. https:\/\/git.io\/v1ve3     (while true; do pip --no-cache-dir install uwsgi==2.0.14 &amp;&amp; break; done)  COPY requirements.txt \/usr\/src\/app\/ RUN pip install --no-cache-dir -r requirements.txt  COPY . \/usr\/src\/app RUN SECRET_KEY=build .\/manage.py collectstatic --noinput &amp;&amp; \\     .\/manage.py makemessages &amp;&amp; \\     apk del .build-deps<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u041f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043a\u0430\u043a \u044d\u0442\u043e \u043f\u0440\u0438\u043d\u044f\u0442\u043e \u0432 \u043c\u0438\u0440\u0435 Python, \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 \u0444\u0430\u0439\u043b\u0435 <code>requirements.txt<\/code>.<\/p>\n<p>  <\/p>\n<h1 id=\"shag-2-docker-compose\">\u0428\u0430\u0433 2: docker-compose<\/h1>\n<p>  <\/p>\n<p>\u0414\u0430\u043b\u0435\u0435, \u0434\u043b\u044f \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0446\u0438\u0438 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 \u0441\u0442\u0435\u043a\u0430 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f <code>docker-compose<\/code>.<br \/>  \u0422\u0435\u043e\u0440\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0438, \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u0438 \u0431\u0435\u0437 \u043d\u0435\u0433\u043e, \u043d\u043e \u0442\u043e\u0433\u0434\u0430 \u0444\u0430\u0439\u043b \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438 \u0434\u043b\u044f CI \u0441\u0442\u0430\u043b \u0431\u044b \u0440\u0430\u0437\u0434\u0443\u0442\u044b\u043c \u0438 \u043d\u0435\u0447\u0438\u0442\u0430\u0435\u043c\u044b\u043c (\u0441\u043c. \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 <a href=\"https:\/\/about.gitlab.com\/2016\/08\/11\/building-an-elixir-release-into-docker-image-using-gitlab-ci-part-1\/\">\u0437\u0434\u0435\u0441\u044c<\/a>). <\/p>\n<p>  <\/p>\n<p>\u0418\u0442\u0430\u043a, \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b <code>docker-compose.yml<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">docker-compose.yml<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code>version: '2' services:     web:         # TODO: \u0421\u043c\u0435\u043d\u0438\u0442\u0435 username \u0438 project \u043d\u0430 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0432\u0430\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f.         image: registry.gitlab.com\/username\/project:${CI_BUILD_REF_NAME}         build: .\/web         ports:             # \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0435 \u043d\u0430\u0440\u0443\u0436\u0443 \u043f\u043e\u0440\u0442\u044b             - &quot;8000:8000&quot;         environment:             # \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f, \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u0440\u043e\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f             #  \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0438\u0437 \u0441\u0435\u0440\u0432\u0435\u0440\u0430             - SECRET_KEY         command: uwsgi \/usr\/src\/app\/uwsgi.ini         volumes:             - static:\/srv\/static         restart: unless-stopped      test:         # TODO: \u0421\u043c\u0435\u043d\u0438\u0442\u0435 username \u0438 project \u043d\u0430 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0432\u0430\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f.         image: registry.gitlab.com\/username\/project:${CI_BUILD_REF_NAME}         command: python manage.py test         restart: &quot;no&quot;      postgres:         image: postgres:9.6         ports:             # \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0435 \u043d\u0430\u0440\u0443\u0436\u0443 \u043f\u043e\u0440\u0442\u044b             - &quot;5432:5432&quot;         environment:             # \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f: \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0438 \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445             - POSTGRES_USER=root             - POSTGRES_DB=database         volumes:             # \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0434\u0430\u043d\u043d\u044b\u0445             - data:\/var\/lib\/postgresql\/data         restart: unless-stopped      nginx:         image: nginx:mainline         ports:             # \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0435 \u043d\u0430\u0440\u0443\u0436\u0443 \u043f\u043e\u0440\u0442\u044b             - &quot;80:80&quot;             - &quot;443:443&quot;         volumes:             # \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u043e\u0432 \u0438 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432             - .\/nginx:\/etc\/nginx:ro             - static:\/srv\/static:ro         depends_on:             - web         restart: unless-stopped<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u0432\u0435\u0434\u0451\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<p>  <\/p>\n<pre><code>repository \u251c\u2500\u2500 nginx \u2502\u00a0\u00a0 \u251c\u2500\u2500 mime.types \u2502\u00a0\u00a0 \u251c\u2500\u2500 nginx.conf \u2502\u00a0\u00a0 \u251c\u2500\u2500 ssl_params \u2502\u00a0\u00a0 \u2514\u2500\u2500 uwsgi_params \u251c\u2500\u2500 web \u2502\u00a0\u00a0 \u251c\u2500\u2500 project \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 __init__.py \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 settings.py \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 urls.py \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 wsgi.py \u2502\u00a0\u00a0 \u251c\u2500\u2500 app \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 migrations \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 ... \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 __init__.py \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 admin.py \u2502   \u2502   \u251c\u2500\u2500 apps.py \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 models.py \u2502\u00a0  \u2502 \u00a0 \u251c\u2500\u2500 tests.py \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 views.py \u2502\u00a0\u00a0 \u251c\u2500\u2500 Dockerfile \u2502\u00a0\u00a0 \u251c\u2500\u2500 manage.py \u2502\u00a0\u00a0 \u251c\u2500\u2500 requirements.txt \u2502\u00a0\u00a0 \u2514\u2500\u2500 uwsgi.ini \u251c\u2500\u2500 docker-compose.yml \u2514\u2500\u2500 fabfile.py<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0435\u0441\u044c \u0441\u0442\u0435\u043a \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 <code>docker-compose up<\/code>, \u0430 \u0432\u043d\u0443\u0442\u0440\u0438 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 \u0441\u0442\u0435\u043a\u0430 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0434\u0440\u0443\u0433\u0438\u043c \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e DNS-\u0438\u043c\u0435\u043d\u0430\u043c, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u0437\u0430\u043f\u0438\u0441\u044f\u043c \u0432 \u0444\u0430\u0439\u043b\u0435 <code>docker-compose.yml<\/code>. \u0422\u0430\u043a, \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0430 Nginx \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">nginx.conf<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code>upstream django {     server web:8000; }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u2026 \u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 Django \u043a \u0411\u0414 \u2014 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">settings.py<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code>DATABASES = {     'default': {         'ENGINE': 'django.db.backends.postgresql',         'NAME': 'database',         'HOST': 'postgres',     } }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 <code>restart: unless-stopped<\/code> \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0432\u0441\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u0442\u0435\u043a\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f \u0441 \u0442\u0435\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043e\u043d\u0438 \u0431\u044b\u043b\u0438 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u044b \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e, \u0442.\u0435. \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0441\u043e\u0432\u0435\u0440\u0448\u0430\u0442\u044c \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f.<\/p>\n<p>  <\/p>\n<h1 id=\"shag-3-gitlab-ci\">\u0428\u0430\u0433 3: GitLab CI<\/h1>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432 \u043a\u043e\u0440\u043d\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0444\u0430\u0439\u043b <code>.gitlab-ci.yml<\/code> \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438 \u0434\u043b\u044f GitLab CI:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">.gitlab-ci.yml<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code># \u0421\u043e\u043e\u0431\u0449\u0430\u0435\u043c Gitlab CI, \u0447\u0442\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Docker \u043f\u0440\u0438 \u0441\u0431\u043e\u0440\u043a\u0435. image: docker:latest services:     - docker:dind  # \u041e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c, \u0438\u0437 \u043a\u0430\u043a\u0438\u0445 \u0441\u0442\u0443\u043f\u0435\u043d\u0435\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u0442\u044c \u043d\u0430\u0448\u0430 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u0430\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f: #  - \u0441\u0431\u043e\u0440\u043a\u0430 Docker-\u043e\u0431\u0440\u0430\u0437\u0430, #  - \u043f\u0440\u043e\u0433\u043e\u043d \u0442\u0435\u0441\u0442\u043e\u0432 Django, #  - \u0432\u044b\u043a\u0430\u0442 \u043d\u0430 \u0431\u043e\u0435\u0432\u043e\u0439 \u0441\u0435\u0440\u0432\u0435\u0440. stages:     - build     - test     - deploy  # \u041e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c #  \u043f\u0435\u0440\u0435\u0434 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0442\u0443\u043f\u0435\u043d\u0438. # \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u0432\u043d\u0435\u0441\u0451\u043d\u043d\u044b\u0435 \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0442\u0443\u043f\u0435\u043d\u0438, \u043d\u0435 \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u043d\u0430 \u0434\u0440\u0443\u0433\u0438\u0435, \u0442\u0430\u043a \u043a\u0430\u043a \u0437\u0430\u043f\u0443\u0441\u043a #  \u0441\u0442\u0443\u043f\u0435\u043d\u0435\u0439 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 \u0447\u0438\u0441\u0442\u043e\u043c Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0435\u0440\u0435\u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437. before_script:     # \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 pip     - apk add --no-cache py-pip     # \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 docker-compose     - pip install docker-compose==1.9.0     # \u043b\u043e\u0433\u0438\u043d \u0432 Gitlab Docker registry     - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY  # \u0421\u0431\u043e\u0440\u043a\u0430 Docker-\u043e\u0431\u0440\u0430\u0437\u0430 build:     stage: build     script:         # \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0441\u0431\u043e\u0440\u043a\u0430         - docker-compose build         # \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0432 registry         - docker-compose push  # \u041f\u0440\u043e\u0433\u043e\u043d \u0442\u0435\u0441\u0442\u043e\u0432 test:     stage: test     script:         # \u0432\u043c\u0435\u0441\u0442\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0439 \u0441\u0431\u043e\u0440\u043a\u0438, \u0437\u0430\u0431\u0438\u0440\u0430\u0435\u043c \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u043d\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0443\u043f\u0435\u043d\u0438                 #  \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 \u0438\u0437 registry         - docker-compose pull test         # \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0442\u0435\u0441\u0442\u044b         - docker-compose run test  # \u0412\u044b\u043a\u0430\u0442 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 deploy:     stage: deploy     # \u0432\u044b\u043a\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u0435\u0442\u043a\u0443 master     only:         - master     # \u0434\u043b\u044f \u044d\u0442\u043e\u0439 \u0441\u0442\u0443\u043f\u0435\u043d\u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438     before_script:         # \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 Fabric, bash \u0438 rsync         - apk add --no-cache openssh-client py-pip py-crypto bash rsync         # \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c Fabric         - pip install fabric==1.12.0         # \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0434\u043b\u044f \u0432\u044b\u043a\u0430\u0442\u0430         - eval $(ssh-agent -s)         - bash -c 'ssh-add &lt;(echo &quot;$DEPLOY_KEY&quot;)'         - mkdir -p ~\/.ssh         - echo -e &quot;Host *\\n\\tStrictHostKeyChecking no\\n\\n&quot; &gt; ~\/.ssh\/config     script:         - fab -H $DEPLOY_ADDR deploy<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0421\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e Docker-runner&#8217;\u044b GitLab CI, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c, \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0441\u043d\u043e\u0432\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0432\u0441\u0451 \u0442\u043e\u0442 \u0436\u0435 \u043e\u0431\u0440\u0430\u0437 <a href=\"https:\/\/hub.docker.com\/_\/alpine\">Alpine Linux<\/a>, \u0447\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0440\u044f\u0434 \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u0435\u0439 \u2014 \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u043d\u0435\u0442 bash, \u043d\u0435\u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u0439 \u043f\u0430\u043a\u0435\u0442\u043d\u044b\u0439 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 <a href=\"https:\/\/wiki.alpinelinux.org\/wiki\/Alpine_Linux_package_management\">apk<\/a>, \u043d\u0435\u043f\u0440\u0438\u0432\u044b\u0447\u043d\u0430\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <a href=\"https:\/\/www.musl-libc.org\">musl-libc<\/a> \u0438 \u0434\u0440. \u0422\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u0438 \u043a\u043e\u043c\u043f\u0435\u043d\u0441\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0442\u0435\u043c, \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0437\u044b \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 Apline Linux \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043b\u0435\u0433\u043a\u043e\u0432\u0435\u0441\u043d\u044b\u043c\u0438; \u0442\u0430\u043a, \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 <code>python:3.5.2-alpine<\/code> <a href=\"https:\/\/microbadger.com\/images\/python\">\u0432\u0435\u0441\u0438\u0442<\/a> \u0432\u0441\u0435\u0433\u043e 27.6 MB.<\/p>\n<p>  <\/p>\n<h1 id=\"shag-4-fabric\">\u0428\u0430\u0433 4: Fabric<\/h1>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0432\u044b\u043a\u0430\u0442\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0443\u0436\u043d\u043e \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0436\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0444\u0430\u0439\u043b <code>fabfile.py<\/code>, \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">fabfile.py<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code>#!\/usr\/bin\/env python2  from fabric.api import hide, env, settings, abort, run, cd, shell_env from fabric.colors import magenta, red from fabric.contrib.files import append from fabric.contrib.project import rsync_project import os  env.user = 'root' env.abort_on_prompts = True # TODO: \u0421\u043c\u0435\u043d\u0438\u0442\u0435 \u043d\u0430 \u043f\u0443\u0442\u044c \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0431\u0443\u0434\u0443\u0442 \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0444\u0430\u0439\u043b\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f PATH = '\/srv\/mywebapp' ENV_FILE = '\/etc\/profile.d\/variables.sh' VARIABLES = ('SECRET_KEY', )  def deploy():     def rsync():         exclusions = ('.git*', '.env', '*.sock*', '*.lock', '*.pyc', '*cache*',                       '*.log',  'log\/', 'id_rsa*', 'maintenance')         rsync_project(PATH, '.\/', exclude=exclusions, delete=True)      def docker_compose(command):         with cd(PATH):             with shell_env(CI_BUILD_REF_NAME=os.getenv(                     'CI_BUILD_REF_NAME', 'master')):                 # \u043f\u0440\u044f\u0447\u0435\u043c \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441-\u0431\u0430\u0440, \u0441\u043c. https:\/\/git.io\/vXH8a                 run('set -o pipefail; docker-compose %s | tee' % command)      # \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435     variables_set = True     for var in VARIABLES + ('CI_BUILD_TOKEN', ):         if os.getenv(var) is None:             variables_set = False             print(red('ERROR: environment variable ' + var + ' is not set.'))     if not variables_set:         abort('Missing required parameters')     with hide('commands'):         run('rm -f &quot;%s&quot;' % ENV_FILE)         append(ENV_FILE,                ['export %s=&quot;%s&quot;' % (var, val) for var, val in zip(                    VARIABLES, map(os.getenv, VARIABLES))])     # Fabric \u043f\u0435\u0440\u0435\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0438\u0437 \u043f\u0440\u043e\u0444\u0438\u043b\u044f \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0432\u044b\u0437\u043e\u0432\u0435 run(),     #  \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u0442 \u0441\u043c\u044b\u0441\u043b\u0430 \u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u044f\u0432\u043d\u043e. \u0441\u043c. http:\/\/stackoverflow.com\/q\/38024726\/1336774      # \u041b\u043e\u0433\u0438\u043d\u0438\u043c\u0441\u044f \u0432 registry     run('docker login -u %s -p %s %s' % (os.getenv('REGISTRY_USER',                                                    'gitlab-ci-token'),                                          os.getenv('CI_BUILD_TOKEN'),                                          os.getenv('CI_REGISTRY',                                                    'registry.gitlab.com')))      # \u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u0443\u044e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443, \u0435\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u043e     with settings(warn_only=True):         with hide('warnings'):             need_bootstrap = run('docker ps | grep -q web').return_code != 0     if need_bootstrap:         print(magenta('No previous installation found, bootstrapping'))         rsync()         docker_compose('up -d')      # \u0412\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0443 &quot;\u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u044b&quot;, \u0441\u043c. https:\/\/habr.ru\/post\/139968     run('touch %s\/nginx\/maintenance &amp;&amp; docker kill -s HUP nginx_1' % PATH)     rsync()     docker_compose('pull')     docker_compose('up -d')     # \u0423\u0431\u0438\u0440\u0430\u0435\u043c \u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0443     run('rm -f %s\/nginx\/maintenance &amp;&amp; docker kill -s HUP nginx_1' % PATH)<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0412\u043e\u043e\u0431\u0449\u0435 \u0433\u043e\u0432\u043e\u0440\u044f, \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c <code>rsync<\/code>&#8216;\u043e\u043c \u0432\u0435\u0441\u044c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0431\u044b\u043b\u043e \u0431\u044b \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0444\u0430\u0439\u043b\u0430 <code>docker-compose.yml<\/code> \u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>nginx<\/code>.<br \/>  \u041a\u043e\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u043d\u0430 \u0441\u043b\u0443\u0447\u0430\u0439, \u0435\u0441\u043b\u0438 \u0432\u0434\u0440\u0443\u0433 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0432\u043d\u0435\u0441\u0442\u0438 \u0441\u0440\u043e\u0447\u043d\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f &quot;\u043d\u0430\u0436\u0438\u0432\u0443\u044e&quot;. \u041d\u0430 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0445 \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430\u0445 gitlab.com \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 CI \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043b\u0430\u0431\u043e\u0435 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0436\u0435\u043b\u0435\u0437\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u0431\u043e\u0440\u043a\u0430, \u0442\u0435\u0441\u0442\u044b \u0438 \u0432\u044b\u043a\u0430\u0442, \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0442 \u0437\u0430 5-10 \u043c\u0438\u043d\u0443\u0442.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/ad8\/d10\/efb\/ad8d10efb8a048da8d40ae381a73a2b6.png\" alt=\"image\"\/><br \/>  <em>(\u043f\u0440\u0430\u0432\u0434\u0430, \u0431\u044b\u0432\u0430\u0435\u0442, \u0447\u0442\u043e \u043e\u043d\u0438 \u0434\u043e \u044d\u0442\u043e\u0433\u043e \u0435\u0449\u0451 \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u0442\u043e\u0440\u0447\u0430\u0442 \u0446\u0435\u043b\u0443\u044e \u0432\u0435\u0447\u043d\u043e\u0441\u0442\u044c)<\/em><\/p>\n<p>  <\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u0431\u044b\u0432\u0430\u044e\u0442 \u0441\u043b\u0443\u0447\u0430\u0438, \u043a\u043e\u0433\u0434\u0430 \u043a\u0430\u0436\u0434\u0430\u044f \u0441\u0435\u043a\u0443\u043d\u0434\u0430 \u043d\u0430 \u0441\u0447\u0435\u0442\u0443 \u2014 \u0434\u043b\u044f \u0442\u0430\u043a\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u043c\u044b \u0438 \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u043b\u0430\u0437\u0435\u0439\u043a\u0443 \u0432 \u0432\u0438\u0434\u0435 \u043f\u043e\u043b\u043d\u044b\u0445 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u043e\u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439, \u0432\u043d\u0435\u0441\u0451\u043d\u043d\u044b\u0445 &quot;\u043d\u0430\u0436\u0438\u0432\u0443\u044e&quot;, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>\/srv\/mywebapp<\/code> \u0438 \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">docker-compose build docker-compose up -d<\/code><\/pre>\n<p>  <\/p>\n<h1 id=\"zaklyuchenie\">\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h1>\n<p>  <\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b\u0438 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u0443\u044e \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 GitLab.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/files\/de7\/3e2\/dd0\/de73e2dd0b7b4742b4cacaf481fa821f.png\" alt=\"image\"\/><\/p>\n<p>  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u043e\u0433\u043e\u043d\u044f\u0442\u044c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0431\u0430\u0442\u0430\u0440\u0435\u044e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 (\u043a\u043e\u0442\u043e\u0440\u044b\u0435, \u0440\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f, \u0442\u043e\u0436\u0435 \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c), \u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0432\u0435\u0442\u043a\u0435 \u0431\u0443\u0434\u0443\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0431\u043e\u0435\u0432\u043e\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u0441 \u043e\u043a\u043e\u043b\u043e\u043d\u0443\u043b\u0435\u0432\u044b\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u044f.<\/p>\n<p>  <\/p>\n<p>\u0417\u0430 \u0440\u0430\u043c\u043a\u0430\u043c\u0438 \u0441\u0442\u0430\u0442\u044c\u0438 \u043e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0444\u0430\u0439\u0440\u0432\u043e\u043b\u0430 \u043d\u0430 \u0446\u0435\u043b\u0435\u0432\u043e\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u0435\u0442\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a PostgreSQL \u0438 uWSGI \u0438\u0437\u0432\u043d\u0435;<\/li>\n<li>\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0440\u043e\u0442\u0430\u0446\u0438\u0438 \u0436\u0443\u0440\u043d\u0430\u043b\u043e\u0432 Nginx;<\/li>\n<li>\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0431\u044d\u043a\u0430\u043f\u043e\u0432 PostgreSQL.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041e\u0441\u0442\u0430\u0432\u0438\u043c \u0438\u0445 \u043f\u044b\u0442\u043b\u0438\u0432\u043e\u043c\u0443 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044e \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0443\u043f\u0440\u0430\u0436\u043d\u0435\u043d\u0438\u044f.<\/p>\n<p>  <\/p>\n<h2 id=\"ssylki\">\u0421\u0441\u044b\u043b\u043a\u0438<\/h2>\n<p>  <\/p>\n<p><a href=\"https:\/\/habrahabr.ru\/company\/softmart\/blog\/310502\">GitLab CI: \u0423\u0447\u0438\u043c\u0441\u044f \u0434\u0435\u043f\u043b\u043e\u0438\u0442\u044c<\/a><br \/>  <a href=\"https:\/\/docs.gitlab.com\/ce\/ci\/quick_start\/README.html\">GitLab CI Quick Start<\/a><br \/>  <a href=\"https:\/\/gitlab.com\/help\/user\/project\/container_registry\">GitLab Container Registry<\/a><br \/>  <a href=\"https:\/\/habrahabr.ru\/post\/226419\">Django \u043d\u0430 production. uWSGI + nginx. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0435 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e<\/a><br \/>  <a href=\"http:\/\/www.fabfile.org\">Fabric documentation<\/a><\/p>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habrahabr.ru\/post\/316054\/\"> https:\/\/habrahabr.ru\/post\/316054\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043e\u043f\u0438\u0448\u0443 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u0442\u0435\u043a\u0435 Django + uWSGI + PostgreSQL + Nginx \u0438\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0435 <a href=\"https:\/\/gitlab.com\">GitLab.com<\/a>. \u0418\u0437\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0435 \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c\u043e \u043a \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u043e\u0439 \u0438\u043d\u0441\u0442\u0430\u043b\u043b\u044f\u0446\u0438\u0438 GitLab. \u041f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044c \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442 \u043e\u043f\u044b\u0442\u043e\u043c \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 Django, \u0430 \u0442\u0430\u043a \u0436\u0435 \u043e\u043f\u044b\u0442\u043e\u043c \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f Linux-\u0441\u0438\u0441\u0442\u0435\u043c.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-281537","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/281537","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=281537"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/281537\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=281537"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=281537"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=281537"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}