cronjob в docker контейнере не может соединиться с другим контейнером - PullRequest
0 голосов
/ 12 марта 2020

Я хочу использовать cronjob для запуска скрипта, который должен извлекать данные из API новостей и передавать их в postegres, который находится в другом контейнере.

, поэтому упрощенная архитектура

 app(in container) -> postegres(in container)

скрипт cronjob находится внутри приложения, он будет извлекать данные и затем отправлять их в postegres.

в моем файле crontab:

* * * * * cd /tourMamaRoot/tourMama/cronjob && fetch_news.py >> /var/log/cron.log 2>&1

Я могу успешно запустить его, вручную запустив скрипт , но когда я помещаю его в crontab, он показывает ошибку.

 File "/usr/local/lib/python3.6/dist-packages/django/db/backends/base/base.py", line 195, in connect
    self.connection = self.get_new_connection(conn_params)
  File "/usr/local/lib/python3.6/dist-packages/django/db/backends/postgresql/base.py", line 178, in get_new_connection
    connection = Database.connect(**conn_params)
  File "/usr/local/lib/python3.6/dist-packages/psycopg2/__init__.py", line 126, in connect
    conn = _connect(dsn, connection_factory=connection_factory, **kwasync)
django.db.utils.OperationalError: could not connect to server: No such file or directory
    Is the server running locally and accepting
    connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?

кажется, что он ищет базу данных только локально, если использует crontab, как я могу установить его для помещения данных в другой контейнер, как я вручную запускаю скрипт?

Информация:

Мой docker контейнер для приложения - это версия Ubuntu 18.04, а следующий файл docker для приложения

FROM ubuntu:18.04
MAINTAINER Eson

ENV PYTHONUNBUFFERED 1
ENV DEBIAN_FRONTEND=noninteractive

EXPOSE 8000

# Setup directory structure
RUN mkdir /tourMamaRoot
WORKDIR /tourMamaRoot/tourMama/

COPY tourMama/requirements/base.txt /tourMamaRoot/base.txt
COPY tourMama/requirements/dev.txt /tourMamaRoot/requirements.txt

# install Python 3
RUN apt-get update && apt-get install -y \
        software-properties-common
RUN add-apt-repository ppa:deadsnakes/ppa
RUN apt-get update && apt-get install -y \
    python3.7 \
    python3-pip
RUN python3.7 -m pip install pip
RUN apt-get update && apt-get install -y \
    python3-distutils \
    python3-setuptools

# install Postgresql
RUN apt-get -y install wget ca-certificates
RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
RUN sh -c echo deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main >> /etc/apt/sources.list.d/pgdg.list
RUN apt-get update
RUN apt-get install -y postgresql postgresql-contrib

# Install some dep
RUN apt-get install net-tools
RUN apt-get install -y libpq-dev python-dev

RUN pip3 install -r /tourMamaRoot/requirements.txt

# Copy application
COPY ./tourMama/ /tourMamaRoot/tourMama/

docker составьте файл:

version: '3'

services:
  app:
    build:
      # current directory
      # if for dev, need to have Dockerfile.dev in folder
      dockerfile: docker/dev/Dockerfile
      context: .
    ports:
      #host to image
      - "8000:8000"
    volumes:
      # map directory to image, which means if something changed in
      # current directory, it will automatically reflect on image,
      # don't need to restart docker to get the changes into effect
      - ./tourMama:/tourMamaRoot/tourMama
    command: >
      sh -c "python3 manage.py wait_for_db &&
             python3 manage.py makemigrations &&
             python3 manage.py migrate &&
             python3 manage.py runserver 0.0.0.0:8000 &&
             sh initial_all.sh"
    environment:
      - DB_HOST=db
      - DB_NAME=app
      - DB_USER=postgres
      - DB_PASS=supersecretpassword

    depends_on:
      - db
      - redis

  db:
    image: postgres:11-alpine
    ports:
      #host to image
      - "5432:5432"
    environment:
      - POSTGRES_DB=app
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=supersecretpassword

  redis:
    image: redis:5.0.5-alpine
    ports:
      #host to image
      - "6379:6379"

#    command: ["redis-server", "--appendonly", "yes"]
#    hostname: redis
#    networks:
#      - redis-net
#    volumes:
#      - redis-data:/data

и мой скрипт cronjob:

import os
import sys
import django
from django.db import IntegrityError
from newsapi.newsapi_client import NewsApiClient
sys.path.append("../")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tourMama.settings")
django.setup()
from news.models import News
from tourMama_app.models import Category
from config.script import categorization_loader

load_category = categorization_loader.load_category_data("catagorization.yml")
categories = list(load_category.keys())
countries = ["us", "gb"]

# Init
newsapi = NewsApiClient(api_key='secret')

for category in categories:
    for country in countries:
        category_lower = category.lower()
        category_obj = Category.objects.filter(
            category=category,
        ).get()

        top_headlines = newsapi.get_top_headlines(q='',
                                                  # sources=object'bbc-news,the-verge',
                                                  category=category_lower,
                                                  language='en',
                                                  page_size=100,
                                                  country=country
                                                  )

        for article in top_headlines.get("articles"):
            try:
                News.objects.create(
                    source=article["source"].get("name") if article["source"] else None,
                    title=article.get("title"),
                    author=article.get("author"),
                    description=article.get("description"),
                    url=article.get("url"),
                    urlToImage=article.get("urlToImage"),
                    published_at=article.get("publishedAt"),
                    content=article.get("content"),
                    category=category_obj
                )

            except IntegrityError:
                print("data already exist")

            else:
                print("data insert successfully")

и, если необходимо, мой django файл настроек выглядит следующим образом:

1 Ответ

0 голосов
/ 12 марта 2020
environment:
  - DB_HOST=db
  - DB_NAME=app
  - DB_USER=postgres
  - DB_PASS=supersecretpassword

Я вижу, что вы передаете переменные окружения через docker -составьте так. Это нормально, когда контейнер запускает команду непосредственно внутри оболочки.

Однако, если поместить ее в crontab, cronjob запустит вашу команду в отдельной оболочке fre sh без передачи среды вообще.

Чтобы обойти эту проблему, вы можете создать отдельный скрипт оболочки:

cat <<EOF > /temp/script.sh
#!/bin/bash
export DB_HOST=db
export DB_NAME=app
export DB_USER=postgres
export DB_PASS=supersecretpassword

cd /tourMamaRoot/tourMama/cronjob && fetch_news.py >> /var/log/cron.log 2>&1
EOF

chmod +x /temp/script.sh

и отредактировать ваш crontab следующим образом:

* * * * * /temp/script.sh
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...