DamienKarrus’s blog

プログラミングとクライミングの足跡

サーバ間のファイルコピー SCP

サーバ間でのファイル転送には、一般的にSFTP、SCPが使われる。
これらのメリットは、

  • SSHプロトコルを使用しているので、認証情報とデータの両方が暗号化される。

  • 秘密鍵を用いての通信が可能

という点にある。
両者の違いは
SCPの方が高速
人間が操作するならどちらもさほど変わらないが、cronで実行するならSCPの方が記述が単純
使用例
秘密鍵でパスワードが必要ない状態において

$ scp data.dat hoge2@hoge.hoge.com:/home/hoge2/doko

あて先はhoge.hoge.comサーバ。ローカル側のログインユーザの秘密鍵で鍵認証して、data.datファイルを/home/hoge2/doko に転送。 SFTPのインタラクティブな仕組みにくらべて非常に単純に記述できる。

次の記事

damienkarrus.hatenablog.com

オリジナルイメージ(3) Apache+PHP+ソースファイルのイメージ作成 Docker入門-11

ApachePHPをインストールして、phpのソールファイル(index.phpのみ)をコピーしたイメージを作ってみる。
ApachePHPはaptを使ってインストールし、その後DocumentRootにPHPをコピーする。
ワークディレクトリをapとする。この中に用意するファイルは2つ。
index.php

<html>
<body>
Your IP <?php echo $_SERVER['REMOTE_ADDR']; ?>
</body>
</html>

Dockerfile

FROM debian
EXPOSE 80
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update \
&& apt install -y apache2 php libapache2-mod-php \
&& apt clean \
&& rm -rf /var/lib/apt/lists/* \
&& rm /var/www/html/index.html
COPY index.php /var/www/html/
CMD /usr/sbin/apachectl -DFOREGROUND
STOPSIGNAL SIGWINCH

内容は次の通り
(1) debianイメージをベースに構築する
(2) ポート80で通信をすることを想定している
(3) aptでワーニングが出ないように変数設定 ← 設定したのにワーニング出た
(4) RUNコマンドにてapache2 php libapache2-mod-php をインストールし、ワークワイルをクリアした後、デフォルトのindex.htmlを削除
(5) ソースファイルであるindex.phpをDocumentRootにコピー
(6) Apacheをフォアグラウンドで実行するよう指定
(7) 終了シグナルをSIGWINCHに変更
イメージを作成してみる

$ cd ap
$ docker build . -t myimg
...(snip)...
Successfully built 90c2d82e3463
Successfully tagged myimg:latest

出来たイメージを確認する

$ docker image ls
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
myimg        latest    90c2d82e3463   3 minutes ago   254MB

コンテナを起動する

$ docker container run -dit --name myphpimg -p 8080:80 myimg

ブラウザでアクセスして動作確認したら削除しておく

$ docker container stop myphpimg
$ docker container rm myphpimg

なお、続けて同じようにビルドをかけると一瞬で出来上がる。これはキャッシュを使用しているためである。もしキャッシュを使用せずに新たにビルドしたいときは --no-cache オプションをつける。

$ docker build . -t myimg --no-cache

次の記事 damienkarrus.hatenablog.com

パスワードなしでSSH/SFTP接続する方法 CentOS

クライアント側で公開鍵と秘密鍵を作成してサーバとクライアントにそれぞれ配置することによってパスワード認証なしでSSH接続できるようになる。
環境はクライアントがCentOS 5.9 (Final)、サーバがCentOS 7.9.2009 (Core)
手順は以下の通り  
クライアント側にて

$ cd ~
$ mkdir .ssh
$ chmod 700 .ssh
$ cd .ssh
$ ssh-keygen -t rsa
$ cat id_rsa.pub

ここで表示された公開鍵の内容をコピペしたいのでコピーしておく   サーバ側にてパスワードなしでログインしたいアカウントにログインする

$ cd ~
$ mkdir .ssh
$ chmod 700 .ssh
$ cd .ssh
$ vi a
(先ほどコピーしたものをペーストする)
:wq
$ touch authorized_keys
$ chmod 600 authorized_keys
$ cat a >> authorized_keys
$ rm a

SSHの設定ファイルに公開鍵による認証の設定をする

# vi /etc/ssh/sshd_config
PubkeyAuthentication yes
AuthorizedKeysFile      .ssh/authorized_keys
:wq
# service sshd restart

これで設定は完了。クライアントから接続してみる

$ ssh hoge@hoge.hoge.hoge
[hoge]$

パスワードなしでログイン完了
これで、SFTPも同様にできるはず。

$ cat sendfile.txt
lcd /home/hoge
cd backup
put hogehoge.gz
bye

$ sftp hoge@hoge.hoge.hoge -b sendfile.txt
sftp> lcd /home/hoge/backup
sftp> cd backup
sftp> put hogehoge.gz
Uploading hogehoge.gz to /home/hoge/backup/hogehoge.gz
sftp> bye

できた。

次の記事

damienkarrus.hatenablog.com

オリジナルイメージ(2) Dockerfileの書式 Docker入門-10

Dockerfileの書式について簡単にまとめる。 書式を説明するにあたり、既存イメージのDockerfileを例にとると、 httpdのイメージのDockerfileはこのようになっている

FROM debian:bullseye-slim

ENV HTTPD_PREFIX /usr/local/apache2
ENV PATH $HTTPD_PREFIX/bin:$PATH
RUN mkdir -p "$HTTPD_PREFIX" \
    && chown www-data:www-data "$HTTPD_PREFIX"
WORKDIR $HTTPD_PREFIX

# install httpd runtime dependencies
# https://httpd.apache.org/docs/2.4/install.html#requirements
RUN set -eux; \
    apt-get update; \
    apt-get install -y --no-install-recommends \
        libaprutil1-ldap \
        libldap-common \
    ; \
    rm -rf /var/lib/apt/lists/*

ENV HTTPD_VERSION 2.4.52
ENV HTTPD_SHA256 0127f7dc497e9983e9c51474bed75e45607f2f870a7675a86dc90af6d572f5c9
ENV HTTPD_PATCHES=""

# see https://httpd.apache.org/docs/2.4/install.html#requirements
RUN set -eux; \
    \
    # mod_http2 mod_lua mod_proxy_html mod_xml2enc
    # https://anonscm.debian.org/cgit/pkg-apache/apache2.git/tree/debian/control?id=adb6f181257af28ee67af15fc49d2699a0080d4c
    savedAptMark="$(apt-mark showmanual)"; \
    apt-get update; \
    apt-get install -y --no-install-recommends \
        bzip2 \
        ca-certificates \
        dirmngr \
        dpkg-dev \
        gcc \


...(snip)...


STOPSIGNAL SIGWINCH

COPY httpd-foreground /usr/local/bin/

EXPOSE 80
CMD ["httpd-foreground"]

FROM debian:bullseye-slim
debian:bullseye-slim をベースイメージにしている

RUN mkdir ...
RUN set -eux; ...
RUN set -eux; ...
→RUNでapacheのパッケージ(ソースコード)からインストールし、パッチを当ててから make install している。

STOPSIGNAL SIGWINCH
→docker stopした場合、コンテナでCMDなどによって実行されているプロセスにSIGTERMシグナルが送信される。apacheの場合は、プロセス停止はSIGWINCHなので、docker stop後に、apacheがtimeoutするまで待つことになる。そこでここで終了シグナルを明記しておくことにより、timeoutを待たずに終了させることが出来る。

EXPOSE 80
→このパッケージはPORT80で通信するよう作られていることがわかる

CMD ["httpd-foreground"]
→docker run したときは httpd-foreground というコマンドが実行される

よく使うコマンドとしては以下の通り   

命令 説明
FROM ベースイメージを指定する
COPY ファイルやフォルダを追加する
ADD ファイルやフォルダを追加する。圧縮ファイルを指定したときは自動的に展開される(tar/tar.gz/tar.bz2/tar.xz) コピー元にURLを指定しファイルをダウンロードできる(圧縮ファイルは展開されない)
RUN イメージをビルドするときに実行する
CMD
ENTRYPOINT
コンテナを起動するときに実行する既定のコマンドを指定する
EXPOSE 通信を想定するポートの初期値を指定する
VOLUME 外部に保存するデータのマウントポイントの初期値を指定する
ENV 環境変数を定義する

COPY/ADDでは、foo/*.php などワイルドカードも指定できる。ADDは挙動が分かり辛くなるため非推奨になるかもしれない。
実行系ではRUNがイメージ作成時に実行され、CMD/ENTRIPOINTはコンテナ起動時に実行される。つまり RUNはイメージの作成に使用される。

 RUN コマンド1 && コマンド2 && コマンド3 

とする。これは、RUN1つごとに差分レイヤーが作られてしまうため、なるべく一連の動作は1つのRUNコマンドにまとめる。 ビルド完了時になんかコマンドを実行したいときは ONBUILD を使う。

 ONBUILD COPY  コピー元 コピー先
 ONBUILD RUN  コマンド 引数・・・

CMDとENTRYPOINT
docker container run の際にイメージの後に実行コマンドを指定するが、CMD は、この実行コマンドのデフォルト値を設定している。もしユーザが異なるコマンドを指定した場合は、ユーザが指定したコマンドが実行される。
一方 ENTRYPOINT によって指定された場合は、必ずここで指定されたコマンドが実行され、ユーザが docker container run した場合に指定されたものがあれば、それはここで指定されているコマンドへのパラメータとして扱われる。
書式は2種類あり、シェル形式の場合は

 CMD コマンド 引数 ・・・

exec形式の場合は

 CMD ["コマンド","引数",・・・]

いずれの書式でも指定できる(ENTRYPOINTも同様)

次の記事

damienkarrus.hatenablog.com

オリジナルイメージ(1)イメージの作成 Docker入門-9

イメージの作り方

イメージの作り方には2種類ある。

  1. コンテナから作成
    コンテナから作成する場合はベースコンテナに修正を加え、新しいイメージとしてアウトプットする。簡単ではあるが、どこにどう手を加えたかの履歴が残らない為、一般にこの方法は利用されない。
  2. Dockerfileから作成 ベースイメージに修正手順(Dockerfile)と修正ファイルを添付して、新しいイメージとしてビルドする。Dockerfileを修正することにより、イメージの修正が可能。
    イメージの作成にあたりDockerの流儀に従うこと。主に次の6点である。
    (1) 1つのコンテナは1つの処理しかしない
    1つのコンテナは1つの処理しかしない
    DBとappは分ける。ただ1つの処理といってもApachePHPは連携して動作するので分けられない。
    (2) 利用するポートを明確にする
    このイメージがどのポートを経由して外部と接続するかを明確にする(後述のEXPOSE参照)。
    (3) 永続化すべき場所を明確にする
    利用者がファイルを置く場所(マウントポイント)を明確にしておく(後述のVOLUME参照)。
    設定は環境変数で渡す
    (4) 設定を受け取るときは環境変数で受け渡しを行う。
    (5) ログは標準出力に出す
    標準出力に出しておけば利用者はdocker logsコマンドで確認できるようになる。
    (6) メインプログラムが終了してしまうとコンテナも終了する
    メインプログラムは終了せずに動き続けないといけない(後述のCMDやENTRYPOINT参照)。

    Dockerfileからイメージを作る

    ApacheのDocumentRootにindex.htmlをいれたイメージを作ってみる。
    (1)作業用ディレクトリを作り必要なファイルを準備する
$ mkdir work
$ cd work
$ cp ../index.html .

Dockerfileをつくる

$ cat Dockerfile
FROM httpd
COPY index.html /usr/local/apache2/htdocs/

ビルドする

$ docker build -t myimage01 .
    ↑ container はつけない!
Sending build context to Docker daemon  3.072kB
Step 1/2 : FROM httpd
latest: Pulling from library/httpd
Digest: sha256:b7907df5e39a98a087dec5e191e6624854844bc8d0202307428dd90b38c10140
Status: Downloaded newer image for httpd:latest
 ---> faed93b28859
Step 2/2 : COPY index.html /usr/local/apache2/htdocs/
 ---> c4aaa7d4ecb4
Successfully built c4aaa7d4ecb4
Successfully tagged myimage01:latest

できたイメージを確認する

$ docker image ls
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
myimage01    latest    c4aaa7d4ecb4   3 minutes ago   144MB

docker history で詳細情報を確認してみる

$ docker history myimage01
IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
c4aaa7d4ecb4   37 minutes ago   /bin/sh -c #(nop) COPY file:0d571419f6b9efc0…   62B

できたイメージを利用する

$ docker container run -dit --name myimage -p 8080:80 myimage01

動作確認出来たらコンテナとイメージを削除

$ docker container stop myimage
$ docker container rm myimage
$ docker image rm myimage01

次の記事

damienkarrus.hatenablog.com

複数の手続きを定義ファイルを使って実行する Docker入門-8

Docker Composeは、あらかじめコンテナの起動豊富や、ネットワークの定義、ボリュームの定義などをYAML形式で書いた手続きファイルを読み込んでを実行するしくみである。
大型計算機で使われていたJCLのコンテナ版のようなもの。
いま、Wordpressサーバを立てる手順でこのDocker Composeを使ってみる

まずはDocker Composeを使わずに立ててみる

使用するコンテナは、
 *Wordpress(httpd入り)
 *Mysql
の2個。これにDBのデータを格納するボリュームが1個
※実際にはアップロードされた情報を格納する外部記憶をVolumeかBindでアタッチする必要があるが今は上記3個とする。
手順としては
 1. 独自ネットワーク構築
 2. ボリューム作成
 3. Mysqlコンテナ作成・起動
 4. Wordpressコンテナ作成・起動

という順序で作業するものとする。

$ docker network create wordpressnet
$ docker volume create wordpress_db_volume
$ docker container run --name wordpress-db -dit --mount type=volume,src=wordpress_db_volume,dst=/var/lib/mysql -e MYSQL_ROOT_PASSWORD=myrootpassword -e MYSQL_DATABASE=wordpressdb -e MYSQL_USER=wordpressuser -e MYSQL_PASSWORD=wordpresspass --net wordpressnet mysql:5.7
$ docker container run --name wordpress-app -dit -p 8080:80 -e WORDPRESS_DB_HOST=wordpress-db -e WORDPRESS_DB_NAME=wordpressdb -e WORDPRESS_DB_USER=wordpressuser -e WORDPRESS_DB_PASSWORD=wordpresspass --net wordpressnet wordpress

動作確認方法はブラウザで上記wordpressの管理画面に入り、動作することを確認する。
ここまで確認できたら一旦削除する。

$ docker container stop wordpress-app  
$ docker container stop wordpress-db  
$ docker container rm wordpress-app  
$ docker container rm wordpress-db  
$ docker volume rm wordpress_db_volume  
$ docker network rm wordpressnet  

つぎにDocker Compose を使って実行してみる

Docker Composeのインストール

まずは Docker Compose をインストールするが、言語パッケージのpythonが必要なのでそれを最初にインストールする。

$ sudo apt install -y python3 python3-pip
$ sudo pip3 install docker-compose
↑書籍ではこのように記述されていたが、
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-c_36wcxj/cryptography/
というエラーが出たため、
$ sudo apt install docker-compose
を実行した
$ docker-compose --version
docker-compose version 1.17.1, build unknown
少し古いようだがこれ進めてみる
作業用ディレクトリと定義ファイルの作成

作業用のディレクトリを作成する

$ cd
$ mkdir wp
$ cd wp

定義ファイルを作る。ファイル名称はデフォルト値の'docker-compose.yml'とする
内容は次の通り

version: "3"

services:
  wordpress-db:
    image: mysql:5.7
    networks:
      - wordpressnet
    volumes:
      - wordpress_db_volume:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: myrootpassword
      MYSQL_DATABASE: wordpressdb
      MYSQL_USER: wordpressuser
      MYSQL_PASSWORD: wordpresspass

  wordpress-app:
    depends_on:
      - wordpress-db
    image: wordpress
    networks:
      - wordpressnet
    ports:
      - 8080:80
    restart: always
    environment:
      WORDPRESS_DB_HOST: wordpress-db
      WORDPRESS_DB_NAME: wordpressdb
      WORDPRESS_DB_USER: wordpressuser
      WORDPRESS_DB_PASSWORD: wordpresspass

networks:
  wordpressnet:

volumes:
  wordpress_db_volume:

ネストを間違えただけで構文エラーになるので注意する。ちなみにnetworks:の前にスペースをつけてネストするとエラーになる(おそらく直前のwordpress-app内の設定として理解しようとしたのだろう)
networks:の指定はなくてもよい。ない場合は、このcompose用のネットワーク(上記の場合wp_default)を作るので、上記と同等の動作をする。

docker-compose の実行

ymlファイルのあるディレクトリでdocker-composeを実行する

$ docker-compose up -d ←デタッチモード
Creating network "wp_wordpressnet" with the default driver
Creating volume "wp_wordpress_db_volume" with default driver
Creating wp_wordpress-db_1 ...
Creating wp_wordpress-db_1 ... done
Creating wp_wordpress-app_1 ...
Creating wp_wordpress-app_1 ... done

稼働状況を確認してみる

$ docker-compose ps
       Name                     Command               State                  Ports
--------------------------------------------------------------------------------------------------
wp_wordpress-app_1   docker-entrypoint.sh apach ...   Up      0.0.0.0:8080->80/tcp,:::8080->80/tcp
wp_wordpress-db_1    docker-entrypoint.sh mysqld      Up      3306/tcp, 33060/tcp

コンテナ名称の前に作業ディレクトリ名がつけられる。
また、末尾の1は1つめのという意味で、scaleオプションをつけた場合は2,_3が生成される。

コンテナの停止と破棄

docker-composeから起動されたコンテナやボリュームはdockerコマンドで停止や削除が出来るが、管理上の反故が生じるのでdocker-composeコマンドで操作すべきである。
上記コンテナにブラウザでアクセスしてwordpressが正常に動作することを確認したらコンテナを停止して破棄する

$ docker-compose down
Stopping wp_wordpress-app_1 ... done
Stopping wp_wordpress-db_1  ... done
Removing wp_wordpress-app_1 ... done
Removing wp_wordpress-db_1  ... done
Removing network wp_wordpressnet

ボリュームは削除されずに残っているので、次回起動時に使用することが出来る。

!!ただし、docker volume prune で消去されてしまうので要注意だ!!

$ docker volume ls
DRIVER    VOLUME NAME
local     f42f26184e4653d0210841a88de2b147e536242fe28c740dcb16dd308e308cf7
local     wp_wordpress_db_volume

何か、ワークのボリュームが残ってしまうようだ・・・

docker-composeのオプションやコマンド

docker-composeコマンドの書式は

 docker-compose オプション コマンド 引数

オプションはあまり使用することがない。引数はコマンドごとに異なる。

docker-composeのコマンド
コマンド 説明
up コンテナを作成し起動する
down コンテナ、ネットワーク、イメージ、ボリュームをまとめて停止し削除する
ps コンテナ一覧を表示する
config Composeファイルの確認と表示をする
port ポートの割り当てを表示する
logs コンテナの出力を表示する
start サービスを開始する
stop サービスを停止する
kill コンテナを強制停止する
exec コマンドを実行する
run コンテナを実行する
create サービスを生成する
restart サービスを再起動する
pause サービスを一時停止する
unpause サービスを再開する
rm 停止中のコンテナを削除する
build サービス用のイメージを構築または再起動する
pull サービス用のイメージをダウンロードする
scale サービス用のコンテナの数を指定する
events コンテナからリアルタイムにイベントを受信する
help ヘルプ

次の記事

damienkarrus.hatenablog.com

コンテナのネットワーク docker入門-7

Dockerには初期状態で3つのネットワークが用意されている

  • bridge: コンテナ生成時に特に指定がなければこのネットワークが使われる

  • host: hostマシンのIPアドレス、portをそのまま使用する。IPマスカレードはできない

  • none: ネットワークは使用しない

bridgeだと各コンテナのIPアドレスでアクセスする必要がある。 コンテナのIPアドレスを知るには docker container inspect コンテナ名 で調べられるが、createする毎に変わってしまうためコンテナ間の通信で使用するには不便である。 新たにdockerネットワークを作れば自動的にDNSサーバが立ってコンテナ名称での名前解決ができる。
dockerネットワークを作る

$ docker network create mynet

または明示的に

$ docker network create mynet --subnet 10.0.0.0/16 --gateway 10.0.0.1

とする。 生成されたネットワーク情報を見るには

$ docker network inspect mynet

...(snip)...
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "10.0.0.0/16",
                    "Gateway": "10.0.0.1"
                }
            ]
        },
...(snip)...

コンテナ生成時にこのmynetを指定する

$ docker container run -dit --name web01 -p 8080:80 --net mynet httpd:2.4
$ docker container run -dit --name web02 -p 8081:80 --net mynet httpd:2.4

ネットワーク接続を確認する

$ docker network inspect mynet

...(snip)...
        "Containers": {
            "08556650cbe98c6cfb623287727a0e04acdf775b40e8fc4a8749e0f969c8891e": {
                "Name": "web02",
                "EndpointID": "3fcb4b7a7d66c8f82a44e934dcf0a82bef04a96f6532c375f744b408fa360b0a",
                "MacAddress": "02:42:0a:00:00:03",
                "IPv4Address": "10.0.0.3/16",
                "IPv6Address": ""
            },
            "7fe34aceb021dcd04c7152b4b18f753ad636f5e274bbe54dbd1cc3e5b3412358": {
                "Name": "web01",
                "EndpointID": "662f2aaf210518da003c0f7696f70dcbb13f568c221a54bc40f057638282dc50",
                "MacAddress": "02:42:0a:00:00:02",
                "IPv4Address": "10.0.0.2/16",
                "IPv6Address": ""
            }
        },
...(snip)...

コンテナからの接続を確認するため第3のコンテナを作る

$ docker container run -rm -it --net mynet ubuntu /bin/bash
# apt update
# apt -y upgrade
# apt install -y iproute2 iputils-ping curl
ping で相通確認
# ping -c 4 web01
80番ポートからレスポンス受信
# curl http://web01/
同様に
# ping -c 4 web02
# curl http://web02/

DNSの確認

# cat /etc/resolv.conf
search ap-northeast-1.compute.internal
nameserver 127.0.0.11
options edns0 ndots:0

nameserverが127.0.0.11に立っている

ネットワークを削除するには

$ docker network rm mynet

次の記事

damienkarrus.hatenablog.com