Как получить доступ к выводу CSV из контейнера Docker?

#python #docker #csv #dockerfile #docker-image

#python #docker #csv #dockerfile #docker-image

Вопрос:

Программа Python генерирует вывод CSV. В настоящее время может выполняться test.py на хост-машине и генерируется файл sample_output.csv.

Однако при реализации программы через контейнеры Docker возникли трудности с поиском файла sample_output.csv. Ниже приведены файл Dockerfile и requirements.txt файлы.

 numpy==1.19.4
pandas==1.2.0
python-dateutil==2.8.1
pytz==2020.5
scipy==1.5.4
six==1.15.0     // -> requirements.txt



FROM python:3

WORKDIR /demo

COPY requirements.txt ./

RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["python" , "-u" ,"./test.py"]   // -> Dockerfile
 

Изображение Docker можно сгенерировать, запустив Docker build -t imagename . Однако при запуске docker run imagename файл csv не генерируется.

Хотел бы обратиться за помощью в поиске файла sample_output.csv после запуска контейнера Docker на основе образа docker.

 //test.py

import pandas as pd
import numpy as np
import os 
from scipy.stats import uniform, exponweib
from scipy.special import gamma
from scipy.optimize import curve_fit


N_SUBSYS = 30
STEPS = 100
LIMIT = 101*STEPS
times = np.arange(0, LIMIT, STEPS)

if not os.path.exists('./output'):
    os.mkdir('./output')

    print("Directory")

class WeibullFailure():
    def __init__(self):
        N_TRAINS = 92
        LOWER_BETA = 0.9
        RANGE_BETA = 0.3
        LOWER_LOGSCALE = 4
        RANGE_LOGSCALE = 1.5
        LOWER_SIZE = 4
        RANGE_SIZE = 8
        gensize = N_TRAINS * int(uniform.rvs(LOWER_SIZE, RANGE_SIZE))
        genbeta = uniform.rvs(LOWER_BETA, RANGE_BETA)
        genscale = np.power(10, uniform.rvs(LOWER_LOGSCALE, RANGE_LOGSCALE))
        self.beta = genbeta
        self.eta = genscale
        self.size = gensize

    def generate_failures(self):
        return exponweib.rvs(
            a=1, loc=0, c=self.beta, scale=self.eta, size=self.size
        )

    def __repr__(self):
        string = f"Subsystem ~ ({self.size} Instances)"
        string  = f" Weibull({self.eta:.2f}, {self.beta:.4f})"
        return string


def get_cumulative_failures(failure_times, times):
    cumulative_failures = {
        i: np.histogram(ft, times)[0].cumsum()
        for i, ft in failure_times.items()
    }
    cumulative_failures = pd.DataFrame(cumulative_failures, index=times[1:])
    return cumulative_failures


def fit_failures(cumulative_failures, subsystems):
    fitted = {}
    for i, x in cumulative_failures.items():
        size = subsystems[i].size
        popt, _ = curve_fit(
            lambda x, a, b: np.exp(a)*np.power(x, b), x.index, x.values
        )
        fitted[i] = (np.exp(-popt[0]/popt[1])*size, popt[1])
    return fitted


def kl_divergence(p1, p2):
    em_constant = 0.57721  # Euler-Mascheroni constant
    eta1, beta1 = p1
    eta2, beta2 = p2
    e11 = np.log(beta1/np.power(eta1, beta1))
    e12 = np.log(beta2/np.power(eta2, beta2))
    e2 = (beta1 - beta2)*(np.log(eta1) - em_constant/beta1)
    e3 = np.power(eta1/eta2, beta2)*gamma(beta2/beta1   1) - 1
    divergence = e11 - e12   e2   e3
    return divergence


subsystems = {i: WeibullFailure() for i in range(N_SUBSYS)}
failure_times = {i: s.generate_failures() for i, s in subsystems.items()}

cumulative_failures = get_cumulative_failures(failure_times, times)
fitted = fit_failures(cumulative_failures, subsystems)
divergences = {
    i: kl_divergence(f, [subsystems[i].eta, subsystems[i].beta])
    for i, f in fitted.items()
}

expected_failures = {i: np.power(times[1:]/s.eta, s.beta)*s.size
                     for i, s in subsystems.items()}
expected_failures = pd.DataFrame(expected_failures, index=times[1:])

modeled_failures = {i: np.power(times[1:]/f[0], f[1])*subsystems[i].size
                    for i, f in fitted.items()}
modeled_failures = pd.DataFrame(modeled_failures, index=times[1:])

cols = ['eta', 'fit_eta', 'beta', 'fit_beta', 'kl_divergence', 'n_instance']
out = pd.concat([
    pd.DataFrame({i: [s.size, s.eta, s.beta] for i, s in subsystems.items()},
                 index=['n_instance', 'eta', 'beta']).T,
    pd.DataFrame(fitted, index=['fit_eta', 'fit_beta']).T,
    pd.Series(divergences, name='kl_divergence')
], axis=1)[cols]
out.to_csv('./output/sample_output.csv')

if not os.path.exists('./output/sample_output.csv'):
    print("Hello")
 

Комментарии:

1. не могли бы вы поделиться test.py файл?

2. Если файл создан, он будет создан внутри контейнера Docker, скорее всего, в /demo , поскольку это WORKDIR .

3. @AntonPomieshchenko добавили test.py файл

4. @KlausD. Выходной файл csv в настоящее время не найден в моем демонстрационном каталоге

5. Как вы проверяете наличие файла внутри контейнера ? Контейнер должен завершиться после завершения программы.

Ответ №1:

Я бы рекомендовал вам перенаправить вывод на консоль вместо файла примерно так:

 from io import StringIO
output = StringIO()
out.to_csv(output)
print(output.getvalue())
 

и чем вам ваш контейнер

 docker run <container> > output.csv
 

Ответ №2:

Контейнеры Docker изолированы от хоста по определению. Когда вы запускаете что-то в контейнере, оно остается в контейнере.

Вы можете смонтировать каталог хоста в контейнер, где, по вашему мнению, должен отображаться вывод скрипта. Вы можете сделать это с -v помощью опции (volume):

 docker run -v /host/path:/container/path ...
 

Можно указать несколько томов:

 docker run -v /host/path:/container/path -v /another/host/path:/another/container/path ...
 

После этого каталог хоста со всем содержимым появится в контейнере в том виде, в каком он находится на хосте, и если ваша программа добавит или заменит что-то там, вы это увидите.

UPD: посмотрите, в test.py каком файле должен быть ваш выходной /demo/output файл, чтобы вы могли смонтировать там какой-нибудь каталог хоста, например, ваш текущий каталог: docker run -v $(pwd):/demo/output ...

Комментарии:

1. для моего сценария, какой будет команда для размещения каталога в контейнере с использованием опции -v?

2. @Clementyong Я обновил вопрос, но посмотрите на другой ответ от Антона Помещенко. Использование перенаправления стандартного вывода более удобно для сценариев, которые создают один файл.