Repository: fidals/shopelectro

Issue:
Улучшить билд систему
Зависит от #248 

----

Как показала практика, для новых разработчиков вникнуть в систему сборки оказалось одной из самых больших задач. Поэтому мы должны упростить ее.
- билдим образы только на CI -> пушим их на docker-hub -> разработчики пулят их у себя на компах. Это поможет избежать проблем со сборкой образов.
- задокументировать систему сборки. Если кому-то придется разбираться в ней, то это будет проще с документацией
- переименовать .env.dist в .env, чтобы не делать лишней работы
- монтировать контейнеры только внутрь проекта. Мы не должны монтировать ничего в корень системы (e.g. `/opt/database/shopelectro:/var/lib/postgresql/data` -> `../database/postgres:/var/lib/postgresql/data`). P.S. Актуально только для `docker-compose.yml`, т.е. для локальной разработки

В идеале процесс доставки зависимостей на компьютер разработчика будет таким:
```bash
docker-compose pull
docker-compose up
```


Discussion:
@artemiy312 , 

> билдим образы только на CI

сейчас основная проблема - это npm. Он по-разному разваливается на разных машинах.
И проблема в том, что, npm-зависимости ставятся при запуске контейнера, а не при билде образа.
В #248 мы собираемся это разрулить.
После неё этот пункт станет возможным, да.

> переименовать .env.dist в .env, чтобы не делать лишней работы

тут проблема в контроле версий. На локальной машине будет .env в вечном modified.
По-моему это не особо удобно.
Тут нужна (полу)интерактивная система чека .env-файла.
Если в нём нету какой-то настройки из шаблона (например `.env.dist`) или какого другого шаблона, он пишет предупреждения.
Эту штуку нам хорошо бы освоить и для всяких config.yml, которые часто встречаются в разных проектах.

С остальным согласен
задача не только (и не столько) о доках.
О доках будет только одна пдд-подзадача, поэтому сниму тег doc
@duker33 
>npm-зависимости ставятся при запуске контейнера, а не при билде

Да, нам нужно устанавливать зависимости на этапе билда.
Еще стоит задуматься о билде статики прямо в образ, чтобы мы могли пушить se-source вместе со статикой, чтобы потом не билдить ее на локале.

На CI это будет выглядеть:
1. Билдим образ nodejs с зависимостями
2. Билдим статику с помощью nodejs образа
3. Кладем собраную статику в se-source образ

На локале:
- `docker-compose pull se-source`
- `docker-compose up -d se-source` будет монтировать статику готовую к работе

Так же пора подумать о версионирование. Это упростит нашу работу :)

>Если в нём нету какой-то настройки из шаблона (например .env.dist) или какого другого шаблона, он пишет предупреждения.

`docker-compose` пишет варнинги, если ты используешь в .yml файле переменные, которых нет в .env файле. Так же мы можем кидать ошибки из мест (e.g. settings.py), где мы используем эти переменные. 
@artemiy312 , со статикой согласен.

> docker-compose пишет варнинги

это да, пишет. Просто можно было сделать покрасивее: писать "check your docker/.env file" и прерывать выполнение билда с ненулевым кодом.
Но если это кажется оверхедом, можем прост забить и ничего не делать. Оставим .env.dist как есть.
В readme написано, что его надо копипастить. Да и знание об env'ах - это область доков Докера, а не нашего проекта

Resolving patch:
diff --git a/shopelectro/celery.py b/shopelectro/celery.py
--- a/shopelectro/celery.py
+++ b/shopelectro/celery.py
@@ -62,8 +62,13 @@
 app.config_from_object('django.conf:settings', namespace='CELERY')
 
 # http://docs.celeryproject.org/en/latest/userguide/configuration.html
+
+BROCKER_URL = (
+    f'amqp://{os.environ["RABBITMQ_DEFAULT_USER"]}:{os.environ["RABBITMQ_DEFAULT_PASS"]}'
+    f'@{os.environ["RABBITMQ_URL"]}:{os.environ["RABBITMQ_PORT"]}/'
+)
 app.conf.update(
-    broker_url=os.environ.get('BROCKER_URL', 'amqp://'),
+    broker_url=BROCKER_URL,
     broker_heartbeat=30,
     task_acks_late=True,
     task_default_queue='default',
diff --git a/shopelectro/settings/base.py b/shopelectro/settings/base.py
--- a/shopelectro/settings/base.py
+++ b/shopelectro/settings/base.py
@@ -159,13 +159,12 @@
 MEDIA_URL = '/media/'
 MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
 
-# It is fake-url. Correct url will be created on `docker-compose up` stage from `docker/.env`
-DATABASE_URL = 'postgres://user:pass@db_name/table'
+DATABASE_URL = (
+    f'postgres://{os.environ["POSTGRES_USER"]}:{os.environ["POSTGRES_PASSWORD"]}'
+    f'@{os.environ["POSTGRES_URL"]}/{os.environ["POSTGRES_DB"]}'
+)
 DATABASES = {
-    'default': dj_database_url.config(
-        env='DATABASE_URL',
-        default=DATABASE_URL,
-    )
+    'default': dj_database_url.parse(DATABASE_URL),
 }
 
 LOGGING = {
@@ -208,7 +207,7 @@
     },
 }
 
-SELENIUM_URL = os.environ.get('SELENIUM_URL', 'http://se-selenium:4444/wd/hub')
+SELENIUM_URL = os.environ.get('SELENIUM_URL', 'http://selenium:4444/wd/hub')
 
 SITE_CREATED = datetime(2013, 1, 1)
 
diff --git a/shopelectro/settings/prod.py b/shopelectro/settings/prod.py
--- a/shopelectro/settings/prod.py
+++ b/shopelectro/settings/prod.py
@@ -18,12 +18,21 @@
 
 USE_CELERY = True
 
-REDIS_PASSWORD = os.environ.get('REDIS_PASSWORD')
+REDIS_URL = os.environ['REDIS_URL']
+REDIS_PORT = os.environ['REDIS_PORT']
+REDIS_PASSWORD = os.environ['REDIS_PASSWORD']
+
+REDIS_DSN = f'redis://{REDIS_URL}:{REDIS_PORT}/'
+
+REDIS_LOCATION_DEFAULT = os.environ['REDIS_LOCATION_DEFAULT']
+REDIS_LOCATION_SESSION = os.environ['REDIS_LOCATION_SESSION']
+REDIS_LOCATION_THUMBNAIL = os.environ['REDIS_LOCATION_THUMBNAIL']
+REDIS_LOCATION_USER_AGENT = os.environ['REDIS_LOCATION_USER_AGENT']
 
 CACHES = {
     'default': {
         'BACKEND': 'django_redis.cache.RedisCache',
-        'LOCATION': os.environ.get('REDIS_LOCATION_DEFAULT', 'redis://127.0.0.1:6379/0'),
+        'LOCATION': f'{REDIS_DSN}{REDIS_LOCATION_DEFAULT}',
         'OPTIONS': {
             'CLIENT_CLASS': 'django_redis.client.DefaultClient',
             'COMPRESSOR': 'django_redis.compressors.zlib.ZlibCompressor',
@@ -32,7 +41,7 @@
     },
     'sessions': {
         'BACKEND': 'django_redis.cache.RedisCache',
-        'LOCATION': os.environ.get('REDIS_LOCATION_SESSION', 'redis://127.0.0.1:6379/1'),
+        'LOCATION': f'{REDIS_DSN}{REDIS_LOCATION_SESSION}',
         'OPTIONS': {
             'CLIENT_CLASS': 'django_redis.client.DefaultClient',
             'SERIALIZER': 'django_redis.serializers.json.JSONSerializer',
@@ -41,7 +50,7 @@
     },
     'thumbnail': {
         'BACKEND': 'django_redis.cache.RedisCache',
-        'LOCATION': os.environ.get('REDIS_LOCATION_THUMBNAIL', 'redis://127.0.0.1:6379/2'),
+        'LOCATION': f'{REDIS_DSN}{REDIS_LOCATION_THUMBNAIL}',
         'OPTIONS': {
             'CLIENT_CLASS': 'django_redis.client.DefaultClient',
             'PASSWORD': REDIS_PASSWORD,
@@ -49,7 +58,7 @@
     },
     'user_agents': {
         'BACKEND': 'django_redis.cache.RedisCache',
-        'LOCATION': os.environ.get('REDIS_LOCATION_USER_AGENT', 'redis://127.0.0.1:6379/3'),
+        'LOCATION': f'{REDIS_DSN}{REDIS_LOCATION_USER_AGENT}',
         'OPTIONS': {
             'CLIENT_CLASS': 'django_redis.client.DefaultClient',
             'PASSWORD': REDIS_PASSWORD,


Test patch:
diff --git a/shopelectro/management/commands/test_db.py b/shopelectro/management/commands/test_db.py
--- a/shopelectro/management/commands/test_db.py
+++ b/shopelectro/management/commands/test_db.py
@@ -66,7 +66,8 @@ def handle(self, *args, **options):
         self.save_dump()
 
     def prepare_db(self):
-        assert settings.DATABASES['default']['NAME'] == 'test'
+        is_test_db = settings.DATABASES['default']['NAME'] == 'test'
+        assert is_test_db, 'To create fixtures you have to create a database named "test".'
         call_command('migrate')
         self.purge_tables()