Dockerコンテナー内でcronジョブを実行する方法


275

シェルスクリプトを呼び出すDockerコンテナー内でcronjobを実行しようとしています。

昨日、私はWeb全体とスタックオーバーフローを検索してきましたが、実際に機能する解決策を見つけることができませんでした。
これどうやってするの?

編集:

私は、(コメントされた)githubリポジトリーを作成しました。これは、所定の間隔でシェル・スクリプトを呼び出す、動作するdocker cronコンテナーを使用しています。

回答:


365

crontabをイメージにコピーして、そのイメージから起動されたコンテナーでジョブを実行することができます。

「を参照してください。ドッカーとcronジョブを実行してから、」ジュリアンBOULAY彼の中にEkito/docker-cron

hello-cron」という名前の新しいファイルを作成して、ジョブを説明しましょう。

* * * * * echo "Hello world" >> /var/log/cron.log 2>&1
# An empty line is required at the end of this file for a valid cron file.

次のDockerfileは、イメージを構築するためのすべての手順を説明しています

FROM ubuntu:latest
MAINTAINER docker@ekito.fr

RUN apt-get update && apt-get -y install cron

# Copy hello-cron file to the cron.d directory
COPY hello-cron /etc/cron.d/hello-cron

# Give execution rights on the cron job
RUN chmod 0644 /etc/cron.d/hello-cron

# Apply cron job
RUN crontab /etc/cron.d/hello-cron

# Create the log file to be able to run tail
RUN touch /var/log/cron.log

# Run the command on container startup
CMD cron && tail -f /var/log/cron.log

Gaafarコメントを参照してください。また、どうすればapt-getインストールのノイズを少なくする
apt-get -y install -qq --force-yes cronことができますか?:うまくいく場合もあります)

で述べたようにネイサン・ロイドコメント

落とし穴に関する簡単なメモ:
スクリプトファイルを追加して、それを実行するようにcronに指示している場合、忘れ場合Cronは警告なしで失敗することに注意してください
RUN chmod 0744 /the_script


または、hugoShaka回答に記載されているように、ジョブ自体がログファイルではなくstdout / stderrに直接リダイレクトされることを確認します。

 * * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2

最後のDockerfile行を

CMD ["cron", "-f"]

参照(about cron -f、つまりcronの「フォアグラウンド」)「docker ubuntu cron -fが機能しない


ビルドして実行します。

sudo docker build --rm -t ekito/cron-example .
sudo docker run -t -i ekito/cron-example

しばらくお待ちください。2分待つと、コマンドラインに次のように表示されます。

Hello world
Hello world

エリックコメントに追加します

tailイメージのビルド中に作成された場合、正しいファイルが表示されない場合があることに注意してください。
その場合は、テールが正しいファイルを取得できるように、コンテナーの実行時にファイルを作成または操作する必要があります。

Dockerの最後の出力が表示さtail -fCMDない」を参照してください。


1
cronは含まれていないため、最初にインストールする必要がありました。しかし、これをDockerfileに追加することで機能します。ありがとう!RUN apt-get update && apt-get install cron
C Heyer 2016年

2
-y
Docker

1
@Gaafar右!私はあなたのコメントを回答に含めて、より見やすくし、別のオプションを加えました。
VonC、

6
このソリューションはまだ機能しますか?指定されたガイドラインに従うと、コンテナーにrootとしてログインしてと入力するとcrontab -lrootcrontabがインストールされていません。また、画面にも表示されません。しかし、「/ etc / cron.d /」を確認すると、crontab /var/log/cron.logファイルが存在することがわかります(さらに驚くべきことにHello World)。このイメージをDockerfileにプルしています:FROM phusion/baseimage:0.10.0。行動の不一致に関するアイデアはありますか?
Homunculus Reticulli

11
2018年以降、このアプローチは機能しなくなりました。誰かが自分のcronjobをUbuntuをベースイメージとして機能させることができましたか?私は箱から出して実行されているcronに付属しているアルパインイメージに興味がありません
ペリカン

148

採用されたソリューションは、運用環境では危険な場合があります

dockerでは、コンテナーごとに1つのプロセスのみを実行する必要があります。そうしないと、分岐してバックグラウンドになったプロセスは監視されず、知らないうちに停止する可能性があります。

あなたが使用する場合はCMD cron && tail -f /var/log/cron.logcronプロセスを基本的に実行するためにforkしcron、バックグラウンドでメインプロセスが終了し、あなたが実行してみましょうtailfフォアグラウンドで。バックグラウンドのcronプロセスが停止したり、失敗したりすることに気付かない場合があります。コンテナは引き続きサイレントで実行され、オーケストレーションツールは再起動しません。

あなたのドッキングウィンドウに直接のcronのコマンドの出力をリダイレクトすることによって、そのようなことを避けることができますstdoutし、stderr中にそれぞれ配置されるの/proc/1/fd/1/proc/1/fd/2

基本的なシェルリダイレクトを使用すると、次のようなことができます。

* * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2

そしてあなたのCMDは次のようになります: CMD ["cron", "-f"]


14
ニース:cron -f「cronフォアグラウンド」用です。わかりやすくするために、あなたの回答を上記に含めました。+1
VonC 2017

私のプログラムが何も出力しないとしましょう。この方法を引き続き使用して、プロセスがバックグラウンドで停止しないことを確認できますか?
Arcsector

1
@Arcsectorこのメソッドは、プロセスをバックグラウンドで配置することを避けます。そのため、サイレントに失敗しません。Dockerコンテナーでバックグラウンドプロセスを使用することは簡単ではありません。バックグラウンドプロセスを実行したい場合は、initプロセスを使用して、コンテナで実行する複数のプロセスを監視することができます。別の方法は、「サイドカー」と呼ばれるメインのコンテナーの横にある別のコンテナーでプロセスを開始することです。多くの場合、最善の方法は、コンテナ内の複数のプロセスを回避することです。
hugoShaka

素敵できれい!大好きです:)
AmaelH

1
これは良い解決策であり、1つの問題を除いて私たちにとってはうまく機能します。コンテナーがSIGTERMシグナルを受信して​​も、スケジュールされたプロセスが終了して正常にシャットダウンするのを待機しているようではなく、問題を引き起こす可能性があるプロセスを強制終了しています。
James Hulse

107

シンプルで軽量なイメージを使用したい場合:

FROM alpine:3.6

# copy crontabs for root user
COPY config/cronjobs /etc/crontabs/root

# start crond with log level 8 in foreground, output to stderr
CMD ["crond", "-f", "-d", "8"]

どこcronジョブは、このフォームでは、あなたのcronジョブを含むファイルです。

* * * * * echo "hello stackoverflow" >> /test_file 2>&1
# remember to end this file with an empty new line

10
シンプルで軽く、標準的な画像ベース。これは受け入れられる答えになるはずです。また、> /proc/1/fd/1 2> /proc/1/fd/2リダイレクトを使用して、Dockerログから直接cronjobs出力にアクセスします。
HenriTel

2
アルパインを使用していない場合:-d 8パラメータをサポートするcrond は標準のcronではなく、busyboxからのcrondコマンドです。たとえば、ubuntuから、これをとして実行できますbusybox crond -f -d 8。古いバージョンでは、を使用する必要があります-L /dev/stdout/
Trendfischer

2
できれば+100をあげます。これは、Docker環境でcronジョブを実行する最良の方法です。
Jitsusama、

1
cronジョブを変更するたびに新しいイメージを作成したくない場合(または複数のジョブが必要な場合)、Alpineを実行し、ボリュームを使用してcronを設定できます。以下を使用してテストしましたdocker run -v ${PWD}/cronjobs:/etc/crontabs/root alpine:3.6 crond -f -d 8。@Groostav Docker Composeでも同様のことができます。
duality_

1
CMD ["crond"またはCMD ["cron"
コードスミス

38

@VonCの提案は素晴らしいですが、私はすべてのcronジョブ設定を1行で行うことを好みます。これにより、cronjobの場所などのクロスプラットフォームの問題が回避され、個別のcronファイルは必要ありません。

FROM ubuntu:latest

# Install cron
RUN apt-get -y install cron

# Create the log file to be able to run tail
RUN touch /var/log/cron.log

# Setup cron job
RUN (crontab -l ; echo "* * * * * echo "Hello world" >> /var/log/cron.log") | crontab

# Run the command on container startup
CMD cron && tail -f /var/log/cron.log

dockerコンテナーを実行した後、次の方法でcronサービスが機能しているかどうかを確認できます。

# To check if the job is scheduled
docker exec -ti <your-container-id> bash -c "crontab -l"
# To check if the cron service is running
docker exec -ti <your-container-id> bash -c "pgrep cron"

CMDではなくENTRYPOINTを使用する場合は、上記のCMDを次のように置き換えることができます

ENTRYPOINT cron start && tail -f /var/log/cron.log

1
興味深い代替案。+1
VonC 2017

2
RUN apt-get update && apt-get -y install cronそれ以外の場合は、パッケージを見つけることができませんcron
alphabetasoup

2
Younessに感謝します。私の場合、各cronが別のファイルで指定されている場合に機能する、次のことを実行するというアイデアを与えてくれました RUN cat $APP_HOME/crons/* | crontab
。Like

cronエントリポイントスクリプトへの追加は、最良のオプションのようです。ENTRYPOINT["entrypoint.sh"]
bozdoz

20

これを行う別の方法は、cron(スケジューラー)をサポートするタスクランナーであるTaskerを使用することです。

どうして ?cronジョブを実行するために、ベースイメージ(python、java、nodejs、ruby)をcrondと混合する必要がある場合があります。それは維持する別のイメージを意味します。Taskerはcrondとコンテナーを分離することでそれを回避します。コマンドを実行するイメージに焦点を当て、それを使用するようにTaskerを構成することができます。

ここでは、docker-compose.ymlいくつかのタスクを実行するファイル

version: "2"

services:
    tasker:
        image: strm/tasker
        volumes:
            - "/var/run/docker.sock:/var/run/docker.sock"
        environment:
            configuration: |
                logging:
                    level:
                        ROOT: WARN
                        org.springframework.web: WARN
                        sh.strm: DEBUG
                schedule:
                    - every: minute
                      task: hello
                    - every: minute
                      task: helloFromPython
                    - every: minute
                      task: helloFromNode
                tasks:
                    docker:
                        - name: hello
                          image: debian:jessie
                          script:
                              - echo Hello world from Tasker
                        - name: helloFromPython
                          image: python:3-slim
                          script:
                              - python -c 'print("Hello world from python")'
                        - name: helloFromNode
                          image: node:8
                          script:
                              - node -e 'console.log("Hello from node")'

そこには3つのタスクがあり、それらのすべてが毎分(every: minute)実行scriptされ、それぞれがimageセクションで定義されたイメージ内でコードを実行します。

を実行してdocker-compose up、動作することを確認してください。完全なドキュメントを含むTaskerリポジトリは次のとおりです。

http://github.com/opsxcq/tasker


Dockerception(別のコンテナーからdockerコンテナーを実行する)は悪い習慣であり、継続的な統合に限定する必要があります。回避策はdocker exec、指定されたコンテナで使用することです。
HenriTel 2018

1
TaskerはDocker(Dind / Dockerception)でDockerを使用していません。Dockerソケットがマッピングとして渡されることに注意してください。生成されたすべてのコンテナーは、Taskerが実行するデーモンで生成されます。また、Docker内でタスカーを実行したくない場合は、他のアプリケーションと同じようにデプロイできます。
OPSXCQ 2018

1
私はタスカーを使用する利点がありません。cronジョブを実行するためだけにjavaとsh ***を使用するのは、本当にやりすぎだと思います。
Karl Adler

cronと必要な基本イメージ(python / nodeなど)を混在させると、維持してデプロイする必要のある追加の依存関係が作成されます。このシナリオでは、すべてのジョブが同じコンテナーを共有します。つまり、後のすべてのクリーンアップについて心配する必要があります。すべてのジョブが実行されます。タスカーで実行されているジョブはべき等なので、心配することは少なくなります。
OPSXCQ

13

VonCの答えはかなり完全です。さらに、私を助けてくれたことが1つあります。ファイルをテーリングせずにcronジョブを実行したいだけの場合&& tail -f /var/log/cron.logは、cronコマンドから単にを削除したくなるでしょう。

ただし、これにより、実行直後にDockerコンテナーが終了します。これは、cronコマンドが完了すると、Dockerが最後のコマンドが終了したと見なし、コンテナーを強制終了するためです。これは、を介してフォアグラウンドでcronを実行することで回避できますcron -f


9

これは、Dockerのexecインターフェースを介してコンテナーで実行中のプロセスの横にあるジョブを実行することを目的としていますが、これは興味深いかもしれません。

コンテナーを監視し、メタデータで定義されたジョブをスケジュールするデーモンを作成しました。例:

version: '2'

services:
  wordpress:
    image: wordpress
  mysql:
    image: mariadb
    volumes:
      - ./database_dumps:/dumps
    labels:
      deck-chores.dump.command: sh -c "mysqldump --all-databases > /dumps/dump-$$(date -Idate)"
      deck-chores.dump.interval: daily

「クラシック」、cronのような構成も可能です。

ここにドキュメントがあります。ここに画像リポジトリがあります


ありがとうございました。この答えは、Dockerコンテナー環境に最も適しています。Dockerイメージに変更はなく、タスクを実行するための特別なコンテナーを追加するだけでdocker exec <container_name> <some_command>、スケジュールによるコマンドのように機能します。
PRIHLOP

これは最も単純で「仕事をやり遂げる」答えです。
Ibrahim Awad

9

他の回答に基づいてDockerイメージを作成しました。これは次のように使用できます

docker run -v "/path/to/cron:/etc/cron.d/crontab" gaafar/cron

ここで/path/to/cron:crontabファイルへの絶対パス、またはDockerfileのベースとして使用できます。

FROM gaafar/cron

# COPY crontab file in the cron directory
COPY crontab /etc/cron.d/crontab

# Add your commands here

参考までに、画像はこちらです。


面白い画像。+1
VonC 2016年

5

コンテナを別のホストにデプロイするときは、プロセスが自動的に開始されないことに注意してください。コンテナ内で「cron」サービスが実行されていることを確認する必要があります。私たちのケースでは、cronサービスを開始するために他のサービスでSupervisordを使用しています。

[program:misc]
command=/etc/init.d/cron restart
user=root
autostart=true
autorestart=true
stderr_logfile=/var/log/misc-cron.err.log
stdout_logfile=/var/log/misc-cron.out.log
priority=998

cronサービスが複数回停止し、致命的な状態になったというスーパーバイザログでエラーが発生しました。ただし、cronは最上位で実行され、cronjobsを正常に実行しているようです。これをありがとう!
lephleg 2017年

はい、同じことが私にも起こりましたが、通常どおり機能するので、気にする必要はありません。
Sagar Ghuge、2017

5

サービスへのdocker execを介してコマンドを実行する専用コンテナーでcronjobを定義します。

これは凝集度が高く、実行中のスクリプトはサービスに定義した環境変数にアクセスできます。

#docker-compose.yml
version: "3.3"
services:
    myservice:
      environment:
        MSG: i'm being cronjobbed, every minute!
      image: alpine
      container_name: myservice
      command: tail -f /dev/null

    cronjobber:
     image: docker:edge
     volumes:
      - /var/run/docker.sock:/var/run/docker.sock
     container_name: cronjobber
     command: >
          sh -c "
          echo '* * * * * docker exec myservice printenv | grep MSG' > /etc/crontabs/root
          && crond -f"

docker swarmを使用してこれを機能させることができませんでした。取得myservice unknownエラーを。
Mark Grimes、

ドッキングウィンドウのソケットを装着する高セキュリティへの影響についての警告があるはずがありますlvh.io/posts/...
カジュアル

4

WindowsでDockerを使用している場合、WindowsからUbuntuコンテナーにcrontabファイルをインポートする場合は、行末の形式をCRLFからLFに(つまり、DOSからUNIXに)変更する必要があることに注意してください。そうでない場合、cronジョブは機能しません。これが実際の例です:

FROM ubuntu:latest

RUN apt-get update && apt-get -y install cron
RUN apt-get update && apt-get install -y dos2unix

# Add crontab file (from your windows host) to the cron directory
ADD cron/hello-cron /etc/cron.d/hello-cron

# Change line ending format to LF
RUN dos2unix /etc/cron.d/hello-cron

# Give execution rights on the cron job
RUN chmod 0644 /etc/cron.d/hello-cron

# Apply cron job
RUN crontab /etc/cron.d/hello-cron

# Create the log file to be able to run tail
RUN touch /var/log/hello-cron.log

# Run the command on container startup
CMD cron && tail -f /var/log/hello-cron.log

Dockerコンテナでcronジョブをデバッグするのは面倒な作業なので、実際に理解するには数時間かかりました。それが彼らのコードを機能させることができない他の誰かを助けることを願っています!


3

上記の例から、私はこの組み合わせを作成しました:

NanoでCrontabを使用した高山画像と編集(viが嫌い)

FROM alpine

RUN apk update
RUN apk add curl nano

ENV EDITOR=/usr/bin/nano 

# start crond with log level 8 in foreground, output to stderr
CMD ["crond", "-f", "-d", "8"]

# Shell Access
# docker exec -it <CONTAINERID> /bin/sh

# Example Cron Entry
# crontab -e
# * * * * * echo hello > /proc/1/fd/1 2>/proc/1/fd/2
# DATE/TIME WILL BE IN UTC

2

ワンタイムジョブと並行してcronをセットアップする

定期的に実行することになっているジョブを含むスクリプトファイル、たとえばrun.shを作成します。

#!/bin/bash
timestamp=`date +%Y/%m/%d-%H:%M:%S`
echo "System path is $PATH at $timestamp"

保存して終了。

CMDの代わりにエントリポイントを使用する

Dockerコンテナー化中に実行する複数のジョブがある場合は、エントリーポイントファイルを使用してそれらをすべて実行します。

エントリポイントファイルは、docker runコマンドが発行されたときに実行されるスクリプトファイルです。したがって、実行するすべてのステップをこのスクリプトファイルに入れることができます。

たとえば、実行する2つのジョブがあります。

ジョブを1回実行:「Dockerコンテナーが開始されました」とエコー

定期的なジョブを実行する:run.sh

entrypoint.shを作成する

#!/bin/bash

# Start the run once job.
echo "Docker container has been started"

# Setup a cron schedule
echo "* * * * * /run.sh >> /var/log/cron.log 2>&1
# This extra line makes it a valid cron" > scheduler.txt

crontab scheduler.txt
cron -f

ファイルに設定されているcrontabを理解しましょう

* * * * *:cronスケジュール。ジョブは毎分実行する必要があります。要件に基づいてスケジュールを更新できます。

/run.sh:定期的に実行されるスクリプトファイルへのパス

/var/log/cron.log:スケジュールされたcronジョブの出力を保存するためのファイル名。

2>&1:エラーログ(ある場合)も、上記で使用したのと同じ出力ファイルにリダイレクトされます。

:余分な新しい行を追加することを忘れないでください。有効なcronになります。 Scheduler.txt:cronセットアップ全体がファイルにリダイレクトされます。

cronでシステム/ユーザー固有の環境変数を使用する

私の実際のcronジョブは、docker runコマンドに渡される環境変数としてほとんどの引数を期待していました。しかし、bashでは、システムまたはDockerコンテナーに属する環境変数を使用できませんでした。

次に、これはこの問題のウォークアラウンドとして登場しました:

  1. entrypoint.shに次の行を追加します
declare -p | grep -Ev 'BASHOPTS|BASH_VERSINFO|EUID|PPID|SHELLOPTS|UID' > /container.env
  1. cronセットアップを更新し、
SHELL=/bin/bash
BASH_ENV=/container.env

ついに、あなたentrypoint.shは次のようになります

#!/bin/bash

# Start the run once job.
echo "Docker container has been started"

declare -p | grep -Ev 'BASHOPTS|BASH_VERSINFO|EUID|PPID|SHELLOPTS|UID' > /container.env

# Setup a cron schedule
echo "SHELL=/bin/bash
BASH_ENV=/container.env
* * * * * /run.sh >> /var/log/cron.log 2>&1
# This extra line makes it a valid cron" > scheduler.txt

crontab scheduler.txt
cron -f

最後になりましたが、Dockerfileを作成してください

FROM ubuntu:16.04
MAINTAINER Himanshu Gupta

# Install cron
RUN apt-get update && apt-get install -y cron

# Add files
ADD run.sh /run.sh
ADD entrypoint.sh /entrypoint.sh

RUN chmod +x /run.sh /entrypoint.sh

ENTRYPOINT /entrypoint.sh

それでおしまい。Dockerイメージをビルドして実行します!


1
@himanshuIIITian私がこれを試したところ、問題は、「1回だけ実行するジョブ」のスクリプトが返されず、corn -fが返されないことです...これは私にはうまくいきません。ありがとう
Doron Levi

@DoronLevi-問題を調査するためにいくつかのログを共有できますか?または、ここからコード全体を確認できます-github.com/nehabhardwaj01/docker-cron
himanshuIIITian

フィードバックをお寄せいただきありがとうございます。答えが役に立てて嬉しいです。
himanshuIIITian

1

cronジョブは/ var / spool / cron / crontabsに保存されます(私が知っているすべてのディストリビューションで共通の場所です)。ところで、あなたはそのようなものを使用してbashでcronタブを作成することができます:

crontab -l > cronexample
echo "00 09 * * 1-5 echo hello" >> cronexample
crontab cronexample
rm cronexample

これにより、cronタスクで一時ファイルが作成され、crontabを使用してプログラムされます。最後の行で一時ファイルを削除します。


cronデーモンは通常、コンテナで実行されません。
マット

@BhargavNanekalvaそれはこの答えが対処しないコンテナーで具体的に設定する必要があります。
マット

@マット、それをコンテナでどのように指定するべきか正確に指摘していただけませんか?。私はcrontab -lを実行し、コマンドが表示されます-kagda.ru/i/6d014816d43_29-06-2017-11:38:59_6d01.png まだ実行されていません
Tebe

@Копать_Шо_я_нашелコンテナーで実行crondしているサービスに加えて、通常はs6などのサービスマネージャーを使用して実行する必要があります。おそらく正しい答えを得るための質問としてそれを尋ねてください
Matt

1

rootアクセスを制限するいくつかのトリミングされたイメージで実行するとき、私はユーザーをsudoersに追加し、次のように実行する必要がありました sudo cron

FROM node:8.6.0
RUN apt-get update && apt-get install -y cron sudo

COPY crontab /etc/cron.d/my-cron
RUN chmod 0644 /etc/cron.d/my-cron
RUN touch /var/log/cron.log

# Allow node user to start cron daemon with sudo
RUN echo 'node ALL=NOPASSWD: /usr/sbin/cron' >>/etc/sudoers

ENTRYPOINT sudo cron && tail -f /var/log/cron.log

多分それは誰かを助ける


ノードイメージはノードユーザーを使用していると思います。そのため、おそらくそのユーザーの権限を追加する必要がありました
bozdoz

1

だから、私の問題は同じでした。修正は、のコマンドセクションを変更することでしたdocker-compose.yml

から

コマンド:crontab / etc / crontab && tail -f / etc / crontab

コマンド:crontab / etc / crontab

コマンド:tail -f / etc / crontab

問題は「&&」コマンド間でした。これを削除した後、すべて大丈夫でした。


-1

これまでに見つけた最も堅牢な方法は、独立したcronコンテナーを実行することです。Dockerクライアントをインストールし、Docker Sockをバインドマウントして、ホスト上のDockerサーバーと通信できるようにします。

次に、各cronジョブのenv varsとエントリポイントスクリプトを使用して、/ etc / crontabを生成します

これは、この原則を使用して作成し、過去3〜4年間生産に使用した画像です。

https://www.vip-consult.solutions/post/better-docker-cron#content


回答は自己完結型で、外部リソースへのリンクではない
Nicolas Bouliane 2017年

-2

時計仕掛けの宝石を使用してタスクをスケジュールしてみてください。このリンクに記載されている手順に従ってください。

http://fuzzyblog.io/blog/rails/2017/05/11/adding-cron-to-a-dockerized-rails-application-using-clockwork.html

以下のようにlib / clock.rbファイル内のrakeタスクを呼び出すことができます。

every(1.day, 'Import large data from csv files', :at => '5:00') do |job|
  `rake 'portal:import_data_from_csv'`
end

docker-composeファイルに別のコンテナーを作成し、コンテナー内で以下のコマンドを実行します。

command: bundle exec clockwork lib/clock.rb

1
スケジューリングに他のツールを使用するのはいい考えです。しかし、この質問は特にcronを要求したので、私の意見では、質問へのコメントとしてあなたの提案がより良いでしょう。
Richard Kiefer
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.