2022年12月28日水曜日

OSSのコンテナレジストリ「Harbor」インストール手順

Docker Hubのようにコンテナイメージを格納し、Dockerにてイメージをダウンロード(Pull)して利用できるようにするサービスをコンテナリポジトリと呼ぶ。

Docker Hubはインターネット上で公開されたサービスとなり、誰でも自由に使える一方、インターネット環境であることからセキュリティ面におけるリスクも大きい。

そのような状況をふまえ、自宅検証環境にプライベートのコンテナレジストリを構築することにした。本記事では、OSSのコンテナレジストリ「Harbor」をインストールする手順を記載する。

なお、今回はHarborへのアクセスをHTTPによる構成としたが、自己署名証明書を使ってHTTPSにて通信させる場合は、以下記事を参照いただきたい。

環境

Harbor自体はDockerコンテナとして動作する。Harbor及びDockerが動作するOSとしてはAlmaLinuxを使用した。

  • OS : AlmaLinux release 8.6
  • Docker : 20.10.21
  • Docker Compose : v2.12.2
  • Harbor : v2.6.2
今回の作業の簡単な概要図を以下に記載する。

Dockerインストール

1. Dockerインストール

Harbor自体もDockerコンテナとして動作するため、まずはDockerのインストールを行う。

# dnf install yum-utils -y
# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# dnf install docker-ce docker-ce-cli containerd.io -y

プロキシ環境の場合は、インターネット接続できるようにsystemdに環境変数の設定を行う。

# sed -ie '/\[Service\]/a Environment="http_proxy=http://192.168.33.23:8080" "https_proxy=http://192.168.33.23:8080" "no_proxy=192.168.0.0/16"' /usr/lib/systemd/system/docker.service
# systemctl start docker
# systemctl enable docker

2. Docker composeのインストール

Harborはインストール時にDocker composeを利用するため、こちらもインストールする。Docker composeは以下の通りdnfコマンドでインストールすることができる。

# dnf install docker-compose-plugin -y

Docker composeのバージョンを確認しておく。

# docker compose version
Docker Compose version v2.12.2

本題とは逸れるが、Docker composeはもともとdocker-composeといったコマンド体系となっていたが、現在のDocker compose V2系では、dockerコマンドに統合されており、docker composeというハイフンなしのコマンド体系になっている。たとえば、docker-compose up -ddocker compose up -dで実行する必要があるので覚えておくとよいだろう。

Compose V2 integrates compose functions into the Docker platform, continuing to support most of the previous docker-compose features and flags. You can run Compose V2 by replacing the hyphen (-) with a space, using docker compose, instead of docker-compose.

Harborインストール

1. Harborのインストーラをダウンロード

Harborのインストーラは、オンラインインストーラとオフラインインストーラの2種類が用意されている。今回はオフラインインストーラを用いる。ダウンロードは以下URLからダウンロードすることができる。

名前に-rcN(Nは数字1桁)が付与されているものは、リリース候補版となる。今回はlatestタグの付与されているバージョン2.6.2をインストールすることにした。オフラインインストーラの容量は約760MBとなる。

2. インストーラを解凍

インストーラはtgz圧縮されているので解凍する。ファイル容量は大きいが、ファイル数自体は多くない。

# tar zxvf harbor-offline-installer-v2.6.2.tgz
harbor/harbor.v2.6.2.tar.gz
harbor/prepare
harbor/LICENSE
harbor/install.sh
harbor/common.sh
harbor/harbor.yml.tmpl

# ls -l harbor
合計 792320
-rw-r--r-- 1 root root     11347 11月  9 18:35 LICENSE
-rw-r--r-- 1 root root      3639 11月  9 18:35 common.sh
-rw-r--r-- 1 root root 811298774 11月  9 18:36 harbor.v2.6.2.tar.gz
-rw-r--r-- 1 root root     10649 11月  9 18:35 harbor.yml.tmpl
-rwxr-xr-x 1 root root      3171 11月  9 18:35 install.sh
-rwxr-xr-x 1 root root      1881 11月  9 18:35 prepare

3. インストール設定ファイル(YAML)を修正

Harborはインストールの設定ファイルとして、harbor.ymlというYAMLファイルの作成が必要となる。

解凍したインストーラ内部に、harbor.yml.tmplというテンプレートが存在するため、これをコピーしてharbor.ymlを作成する。

# cd harbor
# cp harbor.yml.tmpl harbor.yml

以下★箇所を最低限設定しておく。通常Harborへの接続としては、セキュリティの観点からHTTP通信ではなくHTTPS通信を使用すべきであるが、今回は手順簡略化のためHTTP通信による設定を行う。

その他のパラメータについては、公式ドキュメントを参照いただきたい。

harbor.yml

# Configuration file of Harbor

# The IP address or hostname to access admin UI and registry service.
# DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients.
hostname: 192.168.11.54 ←★ホスト名を設定する。DNSなどで名前解決できる場合はFQDN設定が望ましいが、今回はIPアドレスで設定する

# http related config
http:
  # port for http, default is 80. If https enabled, this port will redirect to https port
  port: 80

# https related config
#https: ←★原則はHTTPSによる通信が望ましいが、今回は手順簡略化のためHTTPを使用するためコメントアウト
  # https port for harbor, default is 443
#  port: 443 ←★原則はHTTPSによる通信が望ましいが、今回は手順簡略化のためHTTPを使用するためコメントアウト
  # The path of cert and key files for nginx
#  certificate: /your/certificate/path ★←SSLサーバ証明書を使用しないためコメントアウト
#  private_key: /your/private/key/path ★←SSLサーバ証明書を使用しないためコメントアウト

~(以下略)~

4. インストールスクリプトの実行

harbor.ymlの準備が整ったら、インストールスクリプトを実行する。[Step 0]から[Step 5]まで処理が順に実行される。最後の[Step 5]において、Docker composeによるコンテナ起動がされていることがわかる。

# ./install.sh

[Step 0]: checking if docker is installed ...

Note: docker version: 20.10.21

[Step 1]: checking docker-compose is installed ...

Note: Docker Compose version v2.12.2

[Step 2]: loading Harbor images ...
Loaded image: goharbor/harbor-jobservice:v2.6.2
Loaded image: goharbor/trivy-adapter-photon:v2.6.2
Loaded image: goharbor/chartmuseum-photon:v2.6.2
Loaded image: goharbor/redis-photon:v2.6.2
Loaded image: goharbor/nginx-photon:v2.6.2
Loaded image: goharbor/notary-signer-photon:v2.6.2
Loaded image: goharbor/harbor-core:v2.6.2
Loaded image: goharbor/harbor-db:v2.6.2
Loaded image: goharbor/harbor-registryctl:v2.6.2
Loaded image: goharbor/harbor-exporter:v2.6.2
Loaded image: goharbor/prepare:v2.6.2
Loaded image: goharbor/registry-photon:v2.6.2
Loaded image: goharbor/notary-server-photon:v2.6.2
Loaded image: goharbor/harbor-portal:v2.6.2
Loaded image: goharbor/harbor-log:v2.6.2


[Step 3]: preparing environment ...

[Step 4]: preparing harbor configs ...
prepare base dir is set to /root/harbor
WARNING:root:WARNING: HTTP protocol is insecure. Harbor will deprecate http protocol in the future. Please make sure to upgrade to https
Generated configuration file: /config/portal/nginx.conf
Generated configuration file: /config/log/logrotate.conf
Generated configuration file: /config/log/rsyslog_docker.conf
Generated configuration file: /config/nginx/nginx.conf
Generated configuration file: /config/core/env
Generated configuration file: /config/core/app.conf
Generated configuration file: /config/registry/config.yml
Generated configuration file: /config/registryctl/env
Generated configuration file: /config/registryctl/config.yml
Generated configuration file: /config/db/env
Generated configuration file: /config/jobservice/env
Generated configuration file: /config/jobservice/config.yml
Generated and saved secret to file: /data/secret/keys/secretkey
Successfully called func: create_root_cert
Generated configuration file: /compose_location/docker-compose.yml
Clean up the input dir


Note: stopping existing Harbor instance ...


[Step 5]: starting Harbor ...
[+] Running 10/10
 ? Network harbor_harbor        Created                                    0.0s
 ? Container harbor-log         Started                                    0.3s
 ? Container harbor-db          Started                                    0.9s
 ? Container registry           Started                                    1.0s
 ? Container registryctl        Started                                    0.9s
 ? Container harbor-portal      Started                                    1.0s
 ? Container redis              Started                                    1.0s
 ? Container harbor-core        Started                                    1.4s
 ? Container nginx              Started                                    2.2s
 ? Container harbor-jobservice  Started                                    2.1s
? ----Harbor has been installed and started successfully.----

もし、インストールスクリプト実行後にharbor.ymlを修正した場合は、再度インストールスクリプトを実行することで設定反映ができる。再実行の場合は、一度コンテナが削除されたのち、新しいコンテナが起動される。

# ./install.sh

[Step 0]: checking if docker is installed ...

Note: docker version: 20.10.21

[Step 1]: checking docker-compose is installed ...

Note: Docker Compose version v2.12.2

~(中略)~

Note: stopping existing Harbor instance ...
[+] Running 10/9
 ? Container nginx              Removed                                    0.1s
 ? Container harbor-jobservice  Removed                                    0.1s
 ? Container registryctl        Removed                                   10.1s
 ? Container harbor-portal      Removed                                    0.1s
 ? Container harbor-core        Removed                                    0.1s
 ? Container redis              Removed                                    0.3s
 ? Container harbor-db          Removed                                    0.3s
 ? Container registry           Removed                                    0.3s
 ? Container harbor-log         Removed                                   10.1s
 ? Network harbor_harbor        Removed                                    0.0s


[Step 5]: starting Harbor ...
[+] Running 10/10
 ? Network harbor_harbor        Created                                    0.0s
 ? Container harbor-log         Started                                    0.3s
 ? Container registryctl        Started                                    0.6s
 ? Container harbor-portal      Started                                    1.1s
 ? Container registry           Started                                    1.0s
 ? Container redis              Started                                    1.1s
 ? Container harbor-db          Started                                    1.0s
 ? Container harbor-core        Started                                    1.2s
 ? Container harbor-jobservice  Started                                    1.7s
 ? Container nginx              Started                                    1.7s
? ----Harbor has been installed and started successfully.----

5. DockerをHTTP接続に対応させる設定

Dockerは標準では、コンテナレジストリに対してHTTPSによる接続を行うため、HTTPによる接続をできるよう、/etc/docker/daemon.jsonのファイルを新規作成する。

記載しているIPアドレスは、harbor.ymlhostnameの設定と合わせればよく、IPアドレスまたはFQDNで設定することができる。

# ls -l /etc/docker/daemon.json
ls: '/etc/docker/daemon.json' にアクセスできません: そのようなファイルやディレクトリはありません
# cat << EOF > /etc/docker/daemon.json
{
  "insecure-registries": [
    "192.168.11.54"
  ]
}
EOF

設定後は、Docker及びHarborの再起動が必要となるため、以下の通り再起動を行う。

# systemctl restart docker
# docker compose down -v
# docker compose up -d

6. Web管理画面にログイン

HarborのWeb管理画面にログインする。

  • ユーザ : admin
  • 初期パスワード : Harbor12345
  • 接続先 : http://[HarborをインストールしたOSのIPアドレス]

動作確認

1. プロジェクトを作成

Harborではプロジェクトを作成し、そこにコンテナイメージを保存して管理する構成となっている。デフォルトでlibraryという名称のプロジェクトが存在するが、今回はあえて新規にmyprojectという名称のプロジェクトを作成した。

プロジェクトを作成の際の設定値は以下の通り。

設定項目 設定値 説明
Project Name myproject 任意の名前で設定する。
Access Level Public アクセス権はPublicとする。Publicの場合は、Pullする際にdocker loginコマンドによる認証が不要となる。逆にPublicにしない場合(Privateにする場合)は、Pullの際にdocker loginコマンドによる認証が必要となる。なお、Pushの際はいずれの権限においても事前の認証が必要となる。
Storage Quota -1 GiB 容量の制限(クォータ)の設定となる。今回はデフォルトの無制限(-1)とする。
Proxy Cache 無効 プロキシキャッシュの機能は無効化する。プロキシキャッシュの詳細は、公式マニュアルを参照いただきたい。

2. テスト用コンテナイメージのPull

それでは、Harborを使ってコンテナイメージのアップロード(Push)とダウンロード(Pull)ができることを確認しよう。なお、Push及びPullを行うDockerは、Harborとは別のサーバにインストールしたものとする。

テスト用のコンテナイメージはoraclelinux:8.7を用いる。このコンテナイメージをHarborへPushし、その後一度コンテナイメージを削除してから、HarborよるPullできることを確認する。

まずは、oraclelinux:8.7のコンテナイメージをDocker HubよりPullする。

# docker pull oraclelinux:8.7
8.7: Pulling from library/oraclelinux
4c770e098606: Pull complete
Digest: sha256:07a995ecaf9db1ce613648a08facc162de69f26c39712f1acc93629c2e6c4e73
Status: Downloaded newer image for oraclelinux:8.7
docker.io/library/oraclelinux:8.7

# docker images
REPOSITORY    TAG       IMAGE ID       CREATED       SIZE
oraclelinux   8.7       b0045ea7bbde   10 days ago   225MB

3. DockerをHTTP接続に対応させる設定

Dockerは標準では、コンテナレジストリに対してHTTPSによる接続を行うため、HTTPによる接続をできるよう、/etc/docker/daemon.jsonのファイルを新規作成する。

# ls -l /etc/docker/daemon.json
ls: '/etc/docker/daemon.json' にアクセスできません: そのようなファイルやディレクトリはありません
# cat << EOF > /etc/docker/daemon.json
{
  "insecure-registries": [
    "192.168.11.54"
  ]
}
EOF

設定後は、Dockerの再起動が必要となるため、以下の通り再起動を行う。

# systemctl restart docker

4. Harborへの認証

Pushする場合は、事前にdocker loginコマンドにてHarborに対して認証を成功させておく必要がある。ここで入力するユーザ名とパスワードは、Web管理画面と同じadmin / Harbor12345となる。

# docker login 192.168.11.54
Username: admin
Password: ←★"Harbor12345"を入力
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

5. コンテナイメージをPush

Pushするコンテナイメージに対して、タグの設定を行う。タグは以下の形式で設定する。

[HarborのIPアドレスまたはFQDN]/[プロジェクト名]:[タグ名]

実行結果を以下に記載する。

# docker tag oraclelinux:8.7 192.168.11.54/myproject/oraclelinux:8.7
# docker images
REPOSITORY                            TAG       IMAGE ID       CREATED       SIZE
192.168.11.54/myproject/oraclelinux   8.7       b0045ea7bbde   10 days ago   225MB
oraclelinux                           8.7       b0045ea7bbde   10 days ago   225MB

タグを付与したコンテナイメージをPushする。

# docker push 192.168.11.54/myproject/oraclelinux:8.7
The push refers to repository [192.168.11.54/myproject/oraclelinux]
d8c569c85182: Pushed
8.7: digest: sha256:89787c72978339a100b1855de3ab7749f29752fc83302456bfac6ba209008401 size: 529

特に問題が発生しなければ、HarborのWeb管理画面からも、Pushしたコンテナイメージを確認することができるはずだ。

6. コンテナイメージを削除

次に、先ほどPushしたコンテナイメージをPullしてみよう。

まずは、ローカルに存在するコンテナイメージを削除する。

# docker images
REPOSITORY                            TAG       IMAGE ID       CREATED       SIZE
192.168.11.54/myproject/oraclelinux   8.7       b0045ea7bbde   10 days ago   225MB
oraclelinux                           8.7       b0045ea7bbde   10 days ago   225MB

# docker rmi b0045ea7bbde -f
Untagged: 192.168.11.54/myproject/oraclelinux:8.7
Untagged: 192.168.11.54/myproject/oraclelinux@sha256:89787c72978339a100b1855de3ab7749f29752fc83302456bfac6ba209008401
Untagged: oraclelinux:8.7
Untagged: oraclelinux@sha256:07a995ecaf9db1ce613648a08facc162de69f26c39712f1acc93629c2e6c4e73
Deleted: sha256:b0045ea7bbde263d0543ac9efb749e588d3538bc673f98fe00a73006838a9b89
Deleted: sha256:d8c569c851824688f0f55d46d659a8eef6b8af3ed0a20f389b066f16a4a250e5

# docker images
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

7. HarborよりコンテナイメージをPull

HarborよりコンテナイメージをPullする。

# docker pull 192.168.11.54/myproject/oraclelinux:8.7
8.7: Pulling from myproject/oraclelinux
4c770e098606: Pull complete
Digest: sha256:89787c72978339a100b1855de3ab7749f29752fc83302456bfac6ba209008401
Status: Downloaded newer image for 192.168.11.54/myproject/oraclelinux:8.7
192.168.11.54/myproject/oraclelinux:8.7

# docker images
REPOSITORY                            TAG       IMAGE ID       CREATED       SIZE
192.168.11.54/myproject/oraclelinux   8.7       b0045ea7bbde   10 days ago   225MB

Pullに成功すると、Harbor上でもPullが実行された回数が更新される。

以上で、OSSのコンテナレジストリ「Harbor」をインストールする手順は完了となる。

参考

2022年12月24日土曜日

商用OSのEOSを調べてみた!2022年末版

私は年末に主要な商用OSのEnd of Support (EOS) を調査しており、本記事ではその結果を記載する

結論を先に言うと、2023年中に完全にサポート期限を迎える製品は以下となる。

  • Windows 8.1
  • Windows Server 2012 無印/R2
  • vSphere 6.5/6.7
  • AIX 7.1 TL5
  • HP-UX 11i v2

以下に各製品ごとにEOSを調べた結果を記載した。2023年にサポート期限を迎える製品については、太字で強調表示してある。

なお、本記事で「EOS」と表現する場合は、製品として完全にすべてのサポートが終了する期限を指すことにする。例えば、通常サポートが終了しても延長サポートが存在するような場合は、EOSとは表現しない。

Windows (PC用)

現時点でサポートが残っているWindows OSは、Windows 8.1、Windows 10、Windows 11の3つとなる。2023年の初めに、Windows 8.1がEOSを迎えるので注意。

Windows 8.1

Windows 8.1は固定ライフサイクルポリシーであり、2023年1月まで延長サポートが継続される。

OS名 サポート状況 サポート期限
Windows 8.1 延長サポート 2023/01/10

Windows 10

Windows 10は、モダンライフサイクルポリシーが適用される。なお、今までの単純なメインストリームサポートと延長サポートの構成を「固定ライフサイクルポリシー」と呼ぶ。

モダンライフサイクルポリシーについて簡単に説明すると、Windows 10では3月と9月の年2回、機能更新プログラムのリリースが予定されており、この機能更新プログラムのリリースから18ヶ月 (EnterpriseとEducation Editonについては、9月更新は+1年された30ヶ月) が、その機能更新プログラムを適用したWindows 10のサポート期間となる。

機能更新プログラムは2020年4月まではYYMMの形式で表現されていたが、最新の2020年10月のアップデートからは20H2という名称になっている。2021年は21H1、21H2といった名称でリリースされることになる。

また、Windows 10, version 21H2以降は、今までの半期に1回の機能更新プログラムリリースから、年1回下期のリリースのみに変更された。

以下に現時点におけるサポート中のバージョンを以下に記載する。なお、Windows 11の登場によって、Windows 10 全体としてのEOSも存在するため注意すること。

OS名 サポート期限 (Home and Pro) サポート期限 (Enterprise and Education)
Windows 10 全体 2025/10/14 2025/10/14
Windows 10, version 20H2 2022/05/10 2023/05/09
Windows 10, version 21H2 2023/06/13 2024/06/11
Windows 10, version 22H2 2024/05/14 2025/05/13

Windows 11

Windows 11もモダンライフサイクルポリシーが適用されるが、サポート期間がWindows10より6ヶ月延長され、24ヶ月 (EnterpriseとEducation Editonについては36ヶ月) となった。

OS名 サポート期限 (Home and Pro) サポート期限 (Enterprise and Education)
Windows 11 (Version 21H2) 2023/10/10 2024/10/08
Windows 11 (Version 22H2) 2024/10/08 2025/10/14

Windows Server

Windows Serverは現時点で、Windows Server 2012、2012 R2、2016、2019、2022の5つのバージョンがサポートされる状況となっている。

2023年は、Windows Server 2012の延長サポートが終了する。

OS名 サポート状況 サポート期限
Windows Server 2012 延長サポート 2023/10/10
Windows Server 2012 R2 延長サポート 2023/10/10
Windows Server 2016 延長サポート 2027/01/12
Windows Server 2019 メインストリームサポート 2024/01/09
Windows Server 2019 延長サポート 2029/01/09
Windows Server 2022 メインストリームサポート 2026/10/13
Windows Server 2022 延長サポート 2031/10/14

VMware vSphere

2022年にvSphere 8.0がリリースされた年となった。2023年は、vSphere 6.5及びvSphere 6.7のTECHNICAL GUIDANCEが終了するので注意。

OS名 サポート状況 サポート期限
vSphere 6.5 TECHNICAL GUIDANCE 2023/11/15
vSphere 6.7 TECHNICAL GUIDANCE 2023/11/15
vSphere 7.0 GENERAL SUPPORT 2025/04/02
vSphere 7.0 TECHNICAL GUIDANCE 2027/04/02
vSphere 8.0 GENERAL SUPPORT 2027/10/11
vSphere 8.0 TECHNICAL GUIDANCE 2029/10/11

Red Hat Enterprise Linux

2022年はRHEL 9がリリースされた年となった。現在、RHEL 6は延長サポートフェーズのみとなっているが、2023年にEOSとなる製品は存在しない。

OS名 サポート状況 サポート期限
Red Hat Enterprise Linux 6 Extended Life-cycle Support 2024/06/30
Red Hat Enterprise Linux 7 Maintenance Support 2024/06/30
Red Hat Enterprise Linux 7 Extended Life-cycle Support 2026/06/30
Red Hat Enterprise Linux 8 Maintenance Support 2029/05/31
Red Hat Enterprise Linux 8 Extended Life-cycle Support 2031/05/31
Red Hat Enterprise Linux 9 Maintenance Support 2032/05/31
Red Hat Enterprise Linux 9 Extended Life-cycle Support 2034/05/31

AIX

AIXはTL (Technology Level)毎にサポート期限が異なる。現在サポートが継続しているTLを記載する。AIX 7.2 TL5は昨年までは2023年11月がEOS期限と予想されていたが、TBD(時期未定)に表記が更新されていた。

OS名 サポート状況 サポート期限
AIX 7.1 TL5 Service Pack Support 2023/04/30
AIX 7.2 TL5 Service Pack Support TBD(時期未定)
AIX 7.3 TL0 Service Pack Support 2024/12/31
AIX 7.3 TL1 Service Pack Support 2025/12/31

HP-UX

HP-UXはあまり頻繁なバージョンアップはなく、2007年4月に発表されたHP-UX 11i v3が未だに最新という状況となっている。

長らく延長されてきたHP-UX 11i v2のサポート期限が更新されていないことから、とうとう2023年にサポート期限を迎えるようだ。

OS名 サポート状況 サポート期限
HP-UX 11i v2 延長サポート(開発元支援なし) 2023/12月
HP-UX 11i v3 (HPE Integrity) 標準サポート 2025/12月
HP-UX 11i v3 (HPE Integrity) 延長サポート(開発元支援なし) 2028/12月

以上。

2022年12月17日土曜日

AnsibleでCisco Business 250 (CBS250)を操作する

自宅ではAnsibleを導入してから、以下OSやソフトウェアに対して作業のコード化や自動化を行ってきた。導入手順などは以下記事を参照。

OS/ソフトウェア URL
Linux AnsibleでLinuxサーバの初期設定と単体テストを行う
Windows Server AnsibleからWindows Serverに接続するための事前作業
vSphere ESXi AnsibleでESXi上に仮想マシンを構築する

今回は、Ansibleを使って物理スイッチであるCisco Business 250 (CBS250)を操作する手順を記載する。Cisco Business 250 (CBS250)は、Ansibleに標準で導入されているcommunity.ciscosmbというモジュールで操作可能となる。

注意事項

私の環境では何度かコマンド実行すると、ときおりcommand timeout triggered, timeout value is 30 secs.のエラーでコマンド実行に失敗する事象が発生した。タイムアウト時間を延ばしてもうまくいかないが、しらばく時間を空けると成功するようになることまではわかっているが、解決には至らなかった。

環境

今回手順を確認した環境は以下の通り。

  • コントロールノード
    • OS : AlmaLinux 8.5
    • Ansible : ansible [core 2.13.1]
    • jqコマンドを使うため、あらかじめパッケージをインストールしておく
  • スイッチ
    • 機種 : Cisco Business 250 (CBS250-8T-E-2G)
    • ファームウェアバージョン : 3.2.0.84

事前準備として、あらかじめCBS250に対して以下を実施しておく。

  • SSH接続できるよう設定済みであること
  • SSH用の一般ユーザを作成済みであること
  • enableコマンド実行時のパスワードを設定済みであること

Cisco Business 250のconfigを取得するPlaybook

今回のPlaybookでは、show startup-configを実行して取得したコンフィグをファイルとして保存する。

以下にPlaybookの内容を説明する。

Playbook説明

変数 (vars)

Ansibleを使ってネットワーク機器を操作する際の変数は、以下の通り設定する。ポイントは、ansible_network_oscommunity.ciscosmb.ciscosmbと設定することだ。それ以外は、Cisco IOSなどを操作する際と大きく設定は変わらない。

変数 設定値
ansible_user 任意のSSH接続用ユーザを設定。今回はciscoで設定。
ansible_password 任意のSSH接続用ユーザのパスワードを設定。
ansible_connection network_cli
ansible_network_os community.ciscosmb.ciscosmb
ansible_become_method enable
ansible_become_password enableコマンド実行時のパスワードを設定。

タスク (tasks)

Playbookのタスクは以下の通り。

タスク モジュール 説明
Exec command (show startup-config) community.ciscosmb.command show startup-configを実行した結果を変数に格納する。
Output file cbs250 configuration ansible.builtin.copy コンフィグが保存された変数の内容をファイルに出力する。出力結果はJSON形式になる。
Convert file cbs250 configuration ansible.builtin.shell JSON形式の出力結果をRAW形式に変換する。この処理はAnsibleのshellモジュールを用いてjqコマンドを用いてファイルを整形することで実現した。
Remove temp file ansible.builtin.file 整形前のJSON形式のファイルを削除する。

Playbook

以上をふまえ、Playbook全体は以下となる。

get_cbs250_config.yml

---
- name: Get cisco business 250 configuration
  gather_facts: true
  hosts: cbs250

  vars:
    ansible_user: cisco
    ansible_password: 'P@ssw0rd'
    ansible_connection: network_cli
    ansible_network_os: community.ciscosmb.ciscosmb
    ansible_become_method: enable
    ansible_become_password: 'P@ssw0rd'

    file_cbs250_config: "{{ lookup('env', 'PWD') }}/cbs250/{{ inventory_hostname }}_conf.log"
    file_cbs250_config_tmp: "{{ lookup('env', 'PWD') }}/cbs250/{{ inventory_hostname }}_conf_tmp.log"

  tasks:
    # config取得
    - name: Exec command (show startup-config)
      community.ciscosmb.command:
        commands: show startup-config
      register: result
      become: true

    # configをファイル出力
    - name: Output file cbs250 configuration
      ansible.builtin.copy:
        content: "{{ result.stdout_lines }}"
        dest: "{{ file_cbs250_config_tmp }}"
        mode: '0644'
      delegate_to: localhost

    # JSON形式からRAW形式に変換
    - name: Convert file cbs250 configuration
      ansible.builtin.shell: |
        set -o pipefail && cat "{{ file_cbs250_config_tmp }}" | jq -r .[][] > "{{ file_cbs250_config }}"
      changed_when: false
      delegate_to: localhost

    # 一時ファイルの削除
    - name: Remove temp file
      ansible.builtin.file:
        path: "{{ file_cbs250_config_tmp }}"
        state: absent

実行結果

Playbookの実行結果は以下の通り。

# ansible-playbook -i hosts get_cbs250_config.yml 

PLAY [Get cisco business 250 configuration] *************************************************************************

TASK [Gathering Facts] **********************************************************************************************
ok: [cbs250]

TASK [Exec command (show startup-config)] ***************************************************************************
ok: [cbs250]

TASK [Output file cbs250 configuration] *****************************************************************************
changed: [cbs250 -> localhost]

TASK [Convert file cbs250 configuration] ****************************************************************************
ok: [cbs250 -> localhost]

TASK [Remove temp file] *********************************************************************************************
changed: [cbs250]

PLAY RECAP **********************************************************************************************************
cbs250                  : ok=5    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

CBS250のconfigファイルも以下の通り出力される。

cbs250/cbs250_conf.log

config-file-header
cbs250
v3.2.0.84 / RCBS3.2_950_377_134
CLI v1.0
file SSD indicator encrypted
@
ssd-control-start
ssd config
ssd file passphrase control unrestricted
no ssd file integrity control

~(以下略)~

以上で、Ansibleを使って物理スイッチであるCisco Business 250 (CBS250)を操作する手順は完了となる。

2022年12月10日土曜日

Ansibleを使ってDcokerのコンテナ環境をを操作する

今まで本ブログでは、Ansibleを使ってLinuxやWindows Serverの操作を実施してきた。Ansibleは他にも様々なモジュールが標準で含まれている。

Ansibleに含まれるモジュールは、以下コマンドで確認することができる。

# ansible-galaxy collection list
Collection                    Version
----------------------------- -------
amazon.aws                    3.5.0
ansible.netcommon             3.1.3
ansible.posix                 1.4.0
ansible.utils                 2.7.0
ansible.windows               1.12.0
arista.eos                    5.0.1

~(中略)~

community.docker              2.7.1

~(中略)~

vmware.vmware_rest            2.2.0
vultr.cloud                   1.3.0
vyos.vyos                     3.0.1
wti.remote                    1.0.4

今回は、上記に記載されているcommunity.dockerモジュールを使うことでDockerのコンテナ環境を操作することができる。今回は、Ansibleを使ってDockerのコンテナの環境を操作し、コンテナの停止、ビルド、起動を行うための手順を記載する。

環境

今回手順を確認した環境のOSは以下の通り。

  • コントロールノード
    • OS : AlmaLinux 8.5
    • Ansible : ansible [core 2.13.1]
  • DockerホストOS
    • OS : CentOS Stream release 8
    • Docker : docker-ce-20.10.14

Ansibleコントロールノード構築やLinuxサーバの事前準備の手順は、以下記事を参照いただきたい。

また、Docker上の操作対象のコンテナは以下3つとなる。各コンテナは、あらかじめDockerfileや必要な設定ファイルを準備しておく。必要な設定ファイルについては、それぞれ過去記事を参照いただきたい。

Dockerホストに対する事前準備

AnsibleでDockerを操作する場合、Dcokerホストに対して事前準備作業が必要となる。

1. pipをインストール

Dockerを利用する際はPythonパッケージのインストールが必要となるため、pipをインストールしておく。

# dnf install python3-pip

2. pipを用いてPythonパッケージをインストール

pipを用いて、以下の通りPythonパッケージをインストールする。

# python3 -m pip install docker docker-compose

もしこのモジュールをインストールしていない場合は、Playbook実行時に以下のようにPythonのモジュールが不足するといったエラーが発生する。

fatal: [dockerhost]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"}, "can_talk_to_docker": false, "changed": false, "msg": "Failed to import the required Python library (Docker SDK for Python: docker above 5.0.0 (Python >= 3.6) or docker before 5.0.0 (Python 2.7) or docker-py (Python 2.6)) on t3027dock's Python /usr/libexec/platform-python. Please read the module documentation and install it in the appropriate location. If the required library is installed, but Ansible is using the wrong Python interpreter, please consult the documentation on ansible_python_interpreter, for example via `pip install docker` (Python >= 3.6) or `pip install docker==4.4.4` (Python 2.7) or `pip install docker-py` (Python 2.6). The error was: No module named 'docker'"}
fatal: [dockerhost]: FAILED! => {"changed": false, "msg": "Unable to load docker-compose. Try `pip install docker-compose`. Error: Traceback (most recent call last):\n  File \"/tmp/ansible_community.docker.docker_compose_payload_uyzpmc__/ansible_community.docker.docker_compose_payload.zip/ansible_collections/community/docker/plugins/modules/docker_compose.py\", line 497, in <module>\nModuleNotFoundError: No module named 'compose'\n"}

なお、Pythonパッケージについて、dockerまたはdocker-pyのどちらかをインストールすればよいらしい。ただし、両方のインストールはNGであると明確にAnsibleのマニュアルに記載されているので注意しよう。

docker-py モジュールと docker python モジュールは、同じ名前空間を使用するため、
両方インストールすると、インストールが破損します。両方のパッケージをアンインストールし、
docker-py または docker python モジュールのいずれかを再インストールしてください。
Python 2.6 のサポートが必要でない場合は、
docker モジュールをインストールすることが推奨されます。
いずれかのモジュールをアンインストールするだけでは、
もう一方のモジュールが壊れた状態になる可能性があることに注意してください。

3. Ansible実行ユーザをdockerグループに所属させる

Ansible実行時にAnsible実行ユーザがDockerにアクセスできる権限が必要となる。

# usermod -aG docker ansibleuser
# id ansibleuser
uid=2001(ansibleuser) gid=2001(ansibleuser) groups=2001(ansibleuser),990(docker)

以上でDockerホストに対する事前作業は完了となる。実際にPythonを実行してみよう。

Docker操作用Playbook

1. Playbook説明

今回のPlaybookの実行フローは以下の通り。

各タスクのモジュールと処理の説明を以下表に記載する。

タスク名 モジュール 説明
Copy Dockerfile copy 各コンテナ用のDockerfile及び必要な設定ファイルをディレクトリごとコピーする。
Copy Dockerfile template template 各コンテナ用のDockerfileについて再配置する(変数で指定したベースイメージに設定したファイルを配置する)。
Build docker image docker_image Dockerfileを用いてイメージをビルドする。
Copy docker-compose.yml template template docker-compose.ymlをコピーする。
Down container docker_compose 現在稼働しているコンテナを停止&削除(Down)する。
Up container docker_compose 新しいイメージからコンテナを作成&起動(Up)する。

実際のPlaybookは以下となる。

---
- name: Rebuild docker container
  gather_facts: false
  hosts: docker_servers

  vars:
    ansible_user: ansibleuser

    docker_config:
      image: almalinux
      tag: 8.7

    docker_container:
      - name: "{{ docker_config.image }}-postfix"
        path: container-postfix
      - name: "{{ docker_config.image }}-unbound"
        path: container-unbound
      - name: "{{ docker_config.image }}-squid"
        path: container-squid

    docker_file_path: /tmp/docker

  tasks:
    # Dockerfileコピー
    - name: Copy Dockerfile
      ansible.builtin.copy:
        src: "templates/{{ item.path }}"
        dest: "/tmp/"
        mode: 0644
      loop: "{{ docker_container }}"

    # Dockerfileテンプレートコピー
    - name: Copy Dockerfile template
      ansible.builtin.template:
        src: "templates/{{ item.path }}/Dockerfile"
        dest: "/tmp/{{ item.path }}/"
        mode: 0644
      loop: "{{ docker_container }}"

    # イメージ構築
    - name: Build docker image
      community.docker.docker_image:
        build:
          path: "/tmp/{{ item.path }}"
        source: build
        name: "{{ item.name }}"
        tag: "{{ docker_config.tag }}"
        state: present
      loop: "{{ docker_container }}"

    # docker-compose.ymlテンプレートコピー
    - name: Copy docker-compose.yml template
      ansible.builtin.template:
        src: "templates/compose/docker-compose.yml"
        dest: "/root/compose/"
        mode: 0644
      become: true

    # コンテナ停止&削除
    - name: Down container
      community.docker.docker_compose:
        project_src: /root/compose
        build: false
        # stopped: true # 停止のみ実行する場合
        state: absent
      become: true

    # コンテナ起動
    - name: Up container
      community.docker.docker_compose:
        project_src: /root/compose
        build: false
        state: present
      become: true

2. Playbook実行

# ansible-playbook -i hosts -l dockerhost docker/rebuild_docker_container.yml

PLAY [Rebuild docker container] **********************************************************************************

TASK [Copy Dockerfile] *******************************************************************************************
changed: [dockerhost] => (item={'name': 'almalinux-postfix', 'path': 'container-postfix'})
changed: [dockerhost] => (item={'name': 'almalinux-unbound', 'path': 'container-unbound'})
changed: [dockerhost] => (item={'name': 'almalinux-squid', 'path': 'container-squid'})

TASK [Copy Dockerfile template] **********************************************************************************
changed: [dockerhost] => (item={'name': 'almalinux-postfix', 'path': 'container-postfix'})
changed: [dockerhost] => (item={'name': 'almalinux-unbound', 'path': 'container-unbound'})
changed: [dockerhost] => (item={'name': 'almalinux-squid', 'path': 'container-squid'})

TASK [Build docker image] ****************************************************************************************
ok: [dockerhost] => (item={'name': 'almalinux-postfix', 'path': 'container-postfix'})
ok: [dockerhost] => (item={'name': 'almalinux-unbound', 'path': 'container-unbound'})
ok: [dockerhost] => (item={'name': 'almalinux-squid', 'path': 'container-squid'})

TASK [Copy docker-compose.yml template] **************************************************************************
changed: [dockerhost]

TASK [Down container] ********************************************************************************************
ok: [dockerhost]

TASK [Up container] **********************************************************************************************
changed: [dockerhost]

PLAY RECAP *******************************************************************************************************
dockerhost                 : ok=6    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

3. 結果確認

Playbook実行後のDcokerのコンテナイメージとコンテナの状態を比較してみよう。

まずは実行前の状態を以下に示す。イメージはAlmaLinux 8.6のみとなっており、それぞれのコンテナのタグも8.6になっていることがわかる。

# docker images
REPOSITORY          TAG       IMAGE ID       CREATED         SIZE
almalinux-unbound   8.6       fd58943ebaca   2 months ago    243MB
almalinux-squid     8.6       f6e9116750e0   2 months ago    298MB
almalinux-postfix   8.6       0ca7abe54260   2 months ago    281MB
almalinux           8.6       90516e8d258d   6 months ago    189MB

# docker ps
CONTAINER ID   IMAGE                   COMMAND                  CREATED          STATUS          PORTS                                                                              NAMES
df0976682bfe   almalinux-squid:8.6     "/usr/sbin/squid -N …"   49 minutes ago   Up 49 minutes   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp                                          almalinux-squid
553c80481ac3   almalinux-unbound:8.6   "/usr/sbin/unbound -d"   49 minutes ago   Up 49 minutes   0.0.0.0:10053->53/tcp, 0.0.0.0:10053->53/udp, :::10053->53/tcp, :::10053->53/udp   almalinux-unbound
303103b4abe8   almalinux-postfix:8.6   "/startup.sh"            49 minutes ago   Up 49 minutes   0.0.0.0:25->25/tcp, :::25->25/tcp                                                  almalinux-postfix

次に、Playbook実行後の状態を以下に示す。8.6のイメージに加えて、新たに8.7のイメージが作成されていることがわかる。また、コンテナもタグが8.7に更新されていることが確認できる。

# docker images
REPOSITORY          TAG       IMAGE ID       CREATED          SIZE
almalinux-squid     8.7       7fe03e3252a7   2 seconds ago    292MB
almalinux-unbound   8.7       bed4cd545c1f   17 seconds ago   240MB
almalinux-postfix   8.7       261591afe46c   18 minutes ago   275MB
almalinux           8.7       39f63d416992   3 days ago       190MB
almalinux-unbound   8.6       fd58943ebaca   2 months ago     243MB
almalinux-squid     8.6       f6e9116750e0   2 months ago     298MB
almalinux-postfix   8.6       0ca7abe54260   2 months ago     281MB
almalinux           8.6       90516e8d258d   6 months ago     189MB

# docker ps
CONTAINER ID   IMAGE                   COMMAND                  CREATED          STATUS          PORTS                                                                              NAMES
ec700661b92c   almalinux-unbound:8.7   "/usr/sbin/unbound -d"   25 seconds ago   Up 25 seconds   0.0.0.0:10053->53/tcp, 0.0.0.0:10053->53/udp, :::10053->53/tcp, :::10053->53/udp   almalinux-unbound
1d769e4c9ee6   almalinux-squid:8.7     "/usr/sbin/squid -N …"   25 seconds ago   Up 25 seconds   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp                                          almalinux-squid
9ff38aa8b594   almalinux-postfix:8.7   "/startup.sh"            25 seconds ago   Up 25 seconds   0.0.0.0:25->25/tcp, :::25->25/tcp                                                  almalinux-postfix

以上で、AnsibleにてDockerコンテナを操作する手順は完了となる。

参考

2022年12月3日土曜日

オフライン環境のPythonの仮想環境にAnsibleコントロールノードを構築する

Ansibleはエージェントレスでさまざまな機器の設定を行ことができる非常に強力なツールである。通常、Ansibleコントロールノードを構築する際には、pipを用いてインターネット環境よりインストールする必要があり、インターネットに接続できない環境での利用が難しいという問題がある。
※このようなインターネットと物理的に接続をさせない環境をエアギャップ環境と呼ぶ。

このような環境の場合は、別のインターネットに接続できる環境であらかじめダウンロードしたファイルを持ち込み適用することが一般的である。セキュリティパッチのファイルやウィルス対策ソフトのパターンファイルなども同様の手法で適用することが多い。

AnsibleはPythonをベースに動作するソフトウェアであるため、Pythonの機能を利用することで、エアギャップ環境でのインストールは可能である。

今回は、事前にインターネットに接続できる環境にてAnsibleコントロールノードに必要となるPythonパッケージをダウンロードしておき、それをオフライン環境のLinuxサーバに配置し、Pythonの仮想環境を用いてインストールする方法を紹介する。

以下に作業の概要図を記載する。

環境

今回の動作検証はAlmaLinux 8に対して実施した。ただし、Red Hat系のディストリビューションであるCentOSやRocky Linuxなどでも同様の手順で実施できるだろう。

  • OS : AlmaLinux 8.6
  • Python : 3.8.12
  • Ansible : ansible [core 2.13.5]

AnsibleのPythonパッケージをダウンロード

1. Python 3.8をインストール

AlmaLinux 8.xなどのRed Hat 8.x系のOSでは、Pythonをインストールしても通常3.6がインストールされる。Python 3.6の場合は、Ansible 2.11までであれば動作させることはできるが以下問題がある。

  • Ansible実行時に毎回[DEPRECATION WARNING]の警告メッセージが表示される
  • Ansible 2.11は2022年11月でメンテナンス終了となる

そのため、今回はPython 3.8もインストールし、Ansible 2.13を利用できるようにする。Python 3.8はdnfを使ってインストールできる。

# dnf install python38 -y
メタデータの期限切れの最終確認: 4:28:17 時間前の 2022年10月29日 17時49分52秒 に 実施しました。
依存関係が解決しました。
================================================================================
 パッケージ        Arch   バージョン                            Repo      サイズ
================================================================================
インストール:
 python38          x86_64 3.8.12-1.module_el8.6.0+2778+cd494b30 appstream  78 k
依存関係のインストール:
 python38-libs     x86_64 3.8.12-1.module_el8.6.0+2778+cd494b30 appstream 8.3 M
 python38-pip-wheel
                   noarch 19.3.1-5.module_el8.6.0+2778+cd494b30 appstream 1.0 M
 python38-setuptools-wheel
                   noarch 41.6.0-5.module_el8.6.0+2778+cd494b30 appstream 303 k
弱い依存関係のインストール:
 python38-pip      noarch 19.3.1-5.module_el8.6.0+2778+cd494b30 appstream 1.8 M
 python38-setuptools
                   noarch 41.6.0-5.module_el8.6.0+2778+cd494b30 appstream 667 k
モジュールストリームの有効化中:
 python38                 3.8

~(中略)~

インストール済み:
  python38-3.8.12-1.module_el8.6.0+2778+cd494b30.x86_64
  python38-libs-3.8.12-1.module_el8.6.0+2778+cd494b30.x86_64
  python38-pip-19.3.1-5.module_el8.6.0+2778+cd494b30.noarch
  python38-pip-wheel-19.3.1-5.module_el8.6.0+2778+cd494b30.noarch
  python38-setuptools-41.6.0-5.module_el8.6.0+2778+cd494b30.noarch
  python38-setuptools-wheel-41.6.0-5.module_el8.6.0+2778+cd494b30.noarch

完了しました!

2. pipをバージョンアップ

ダウンロードやインストール作業で失敗することがあるため、pipを最新版にしておく。

# pip-3.8 install -U pip
WARNING: Running pip install with root privileges is generally not a good idea. Try `pip-3.8 install --user` instead.
Collecting pip
  Downloading https://files.pythonhosted.org/packages/47/ef/8b5470b5b94b36231ed9c0bde90caa71c0d4322d4a15f009b2b7f4287fe0/pip-22.3-py3-none-any.whl (2.1MB)
     |????????????????????????????????| 2.1MB 10.9MB/s
Installing collected packages: pip
Successfully installed pip-22.3

3. Ansibleコントロールノード構築用のPythonパッケージをダウンロード

ダウンロードしたファイルを保管するディレクトリを以下の通り作成する。

# mkdir ansible-pack

Pythonパッケージはpip downloadコマンドを実行することでダウンロードできる。今回は以下3点のパッケージをダウンロードする。

  • pip
  • ansible
  • pywinrm

以下に実行結果を記載する。

pip

# pip-3.8 download -d ./ansible-pack pip
WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.
Collecting pip
  Using cached pip-22.3-py3-none-any.whl (2.1 MB)
Saved ./ansible-pack/pip-22.3-py3-none-any.whl
Successfully downloaded pip

ansible

# pip-3.8 download -d ./ansible-pack ansible
WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.
Collecting ansible
  Downloading ansible-6.5.0-py3-none-any.whl (44.9 MB)
     qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq 44.9/44.9 MB 30.7 MB/s eta 0:00:00
Collecting ansible-core~=2.13.5
  Downloading ansible_core-2.13.5-py3-none-any.whl (2.1 MB)
     qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq 2.1/2.1 MB 28.6 MB/s eta 0:00:00

~(中略)~

Saved ./ansible-pack/pycparser-2.21-py2.py3-none-any.whl
Successfully downloaded ansible ansible-core jinja2 PyYAML resolvelib cryptography packaging cffi MarkupSafe pyparsing pycparser

pywinrm

# pip-3.8 download -d ./ansible-pack pywinrm
WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.
Collecting pywinrm
  Using cached pywinrm-0.4.3-py2.py3-none-any.whl (44 kB)

~(中略)~

Saved ./ansible-pack/urllib3-1.26.12-py2.py3-none-any.whl
Successfully downloaded pywinrm requests requests-ntlm six xmltodict certifi charset-normalizer cryptography idna ntlm-auth urllib3 cffi pycparser

ダウンロードしたファイルは合計53MBとなった。

# du -h ansible-pack/
53M     ansible-pack/

4. ダウンロードしたPythonパッケージを圧縮して持ち出し

持ち出ししやすいようtarを使ってパッケージを圧縮する。

# tar zcvf ansible-pack.tgz ansible-pack/
ansible-pack/
ansible-pack/pip-22.3-py3-none-any.whl
ansible-pack/ansible-6.5.0-py3-none-any.whl
ansible-pack/ansible_core-2.13.5-py3-none-any.whl
ansible-pack/Jinja2-3.1.2-py3-none-any.whl
ansible-pack/PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl
ansible-pack/resolvelib-0.8.1-py2.py3-none-any.whl
ansible-pack/cryptography-38.0.1-cp36-abi3-manylinux_2_28_x86_64.whl
ansible-pack/packaging-21.3-py3-none-any.whl
ansible-pack/cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
ansible-pack/MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
ansible-pack/pyparsing-3.0.9-py3-none-any.whl
ansible-pack/pycparser-2.21-py2.py3-none-any.whl
ansible-pack/pywinrm-0.4.3-py2.py3-none-any.whl
ansible-pack/requests-2.28.1-py3-none-any.whl
ansible-pack/requests_ntlm-1.1.0-py2.py3-none-any.whl
ansible-pack/six-1.16.0-py2.py3-none-any.whl
ansible-pack/xmltodict-0.13.0-py2.py3-none-any.whl
ansible-pack/certifi-2022.9.24-py3-none-any.whl
ansible-pack/charset_normalizer-2.1.1-py3-none-any.whl
ansible-pack/idna-3.4-py3-none-any.whl
ansible-pack/ntlm_auth-1.5.0-py2.py3-none-any.whl
ansible-pack/urllib3-1.26.12-py2.py3-none-any.whl

圧縮したファイルを任意の手法で持ち出しを行い、オフライン環境のLinuxサーバに配置しておこう。

ダウンロードしたPythonパッケージをPythonの仮想環境にインストール

続けて、ダウンロードしたPythonパッケージをPythonの仮想環境にインストールする手順を説明する。

1. 前提パッケージ確認

Ansible 2.13を動作させるためには、最低限以下2つのパッケージインストールが必要となる。

  • Python 3.8
  • sshpass

Python 3.8は前述の通り、Ansible の動作条件として必要となる。sshpassは、AnsibleからLinuxなどの機器に対してパスワード認証方式を用いてSSH接続する際に必要となる。

# dnf install --disablerepo=dvd* python38 -y
# dnf install --disablerepo=dvd* sshpass -y

2. ダウンロードしたファイルを展開

インターネット環境からダウンロードしたファイルを展開する。

# tar zxvf ansible-pack.tgz
ansible-pack/
ansible-pack/pip-22.3-py3-none-any.whl
ansible-pack/ansible-6.5.0-py3-none-any.whl
ansible-pack/ansible_core-2.13.5-py3-none-any.whl
ansible-pack/Jinja2-3.1.2-py3-none-any.whl
ansible-pack/PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl
ansible-pack/resolvelib-0.8.1-py2.py3-none-any.whl
ansible-pack/cryptography-38.0.1-cp36-abi3-manylinux_2_28_x86_64.whl
ansible-pack/packaging-21.3-py3-none-any.whl
ansible-pack/cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
ansible-pack/MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
ansible-pack/pyparsing-3.0.9-py3-none-any.whl
ansible-pack/pycparser-2.21-py2.py3-none-any.whl
ansible-pack/pywinrm-0.4.3-py2.py3-none-any.whl
ansible-pack/requests-2.28.1-py3-none-any.whl
ansible-pack/requests_ntlm-1.1.0-py2.py3-none-any.whl
ansible-pack/six-1.16.0-py2.py3-none-any.whl
ansible-pack/xmltodict-0.13.0-py2.py3-none-any.whl
ansible-pack/certifi-2022.9.24-py3-none-any.whl
ansible-pack/charset_normalizer-2.1.1-py3-none-any.whl
ansible-pack/idna-3.4-py3-none-any.whl
ansible-pack/ntlm_auth-1.5.0-py2.py3-none-any.whl
ansible-pack/urllib3-1.26.12-py2.py3-none-any.whl

3. Pythonの仮想環境を作成

Pythonの仮想環境は、python -m venv [インストールディレクトリ名]とすることですぐに作成できる。

今回はディレクトリ名を.venvとし、Python 3.8を利用する必要があるので、python3.8コマンドを使って以下通りコマンドを実行した。

# python3.8 -m venv .venv
# ls -l .venv/
合計 4
drwxr-xr-x 2 root root 210 10月 29 22:15 bin
drwxr-xr-x 2 root root   6 10月 29 22:15 include
drwxr-xr-x 3 root root  23 10月 29 22:15 lib
lrwxrwxrwx 1 root root   3 10月 29 22:15 lib64 -> lib
-rw-r--r-- 1 root root  70 10月 29 22:15 pyvenv.cfg

4. Pythonの仮想環境を有効化

Pythonの仮想環境を有効化する際には、source [インストールディレクトリ]/bin/activateを実行する。実行すると、プロンプトに(.venv)が表示される。

[root@locahost ~]# source .venv/bin/activate
(.venv) [root@locahost ~]#

以降はPythonの仮想環境での作業については、(.venv)#でプロンプトを表記する。

5. Pythonの仮想環境にPythonパッケージをインストール

Pythonの仮想環境にて、ダウンロードしておいた以下のPythonパッケージをインストールしていく。

  • pip
  • ansible
  • pywinrm

通常のPythonパッケージと同様、pip installでインストールするが、以下オプションを付与する点に注意する。

オプション 説明
--no-index インターネット環境のパッケージインデックス(PyPI; Python Package Index)の検索を行わない。
--find-links=[パッケージディレクトリ] パッケージを検索するローカルディレクトリを指定する。

pip

(.venv)# pip install --no-index --find-links=./ansible-pack/ -U pip
Looking in links: ./ansible-pack/
Processing ./ansible-pack/pip-22.3-py3-none-any.whl
Installing collected packages: pip
  Found existing installation: pip 19.3.1
    Uninstalling pip-19.3.1:
      Successfully uninstalled pip-19.3.1
Successfully installed pip-22.3

ansible

(.venv)# pip install --no-index --find-links=./ansible-pack/ ansible
Looking in links: ./ansible-pack/
Processing ./ansible-pack/ansible-6.5.0-py3-none-any.whl
Processing ./ansible-pack/ansible_core-2.13.5-py3-none-any.whl
Processing ./ansible-pack/resolvelib-0.8.1-py2.py3-none-any.whl
Processing ./ansible-pack/cryptography-38.0.1-cp36-abi3-manylinux_2_28_x86_64.whl
Processing ./ansible-pack/PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl
Processing ./ansible-pack/Jinja2-3.1.2-py3-none-any.whl
Processing ./ansible-pack/packaging-21.3-py3-none-any.whl
Processing ./ansible-pack/MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Processing ./ansible-pack/cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Processing ./ansible-pack/pyparsing-3.0.9-py3-none-any.whl
Processing ./ansible-pack/pycparser-2.21-py2.py3-none-any.whl
Installing collected packages: resolvelib, PyYAML, pyparsing, pycparser, MarkupSafe, packaging, jinja2, cffi, cryptography, ansible-core, ansible
Successfully installed MarkupSafe-2.1.1 PyYAML-6.0 ansible-6.5.0 ansible-core-2.13.5 cffi-1.15.1 cryptography-38.0.1 jinja2-3.1.2 packaging-21.3 pycparser-2.21 pyparsing-3.0.9 resolvelib-0.8.1

pywinrm

(.venv)# pip install --no-index --find-links=./ansible-pack/ pywinrm
Looking in links: ./ansible-pack/
Processing ./ansible-pack/pywinrm-0.4.3-py2.py3-none-any.whl
Processing ./ansible-pack/requests_ntlm-1.1.0-py2.py3-none-any.whl
Processing ./ansible-pack/six-1.16.0-py2.py3-none-any.whl
Processing ./ansible-pack/requests-2.28.1-py3-none-any.whl
Processing ./ansible-pack/xmltodict-0.13.0-py2.py3-none-any.whl
Processing ./ansible-pack/urllib3-1.26.12-py2.py3-none-any.whl
Processing ./ansible-pack/idna-3.4-py3-none-any.whl
Processing ./ansible-pack/certifi-2022.9.24-py3-none-any.whl
Processing ./ansible-pack/charset_normalizer-2.1.1-py3-none-any.whl
Processing ./ansible-pack/ntlm_auth-1.5.0-py2.py3-none-any.whl
Requirement already satisfied: cryptography>=1.3 in ./.venv/lib/python3.8/site-packages (from requests-ntlm>=1.1.0->pywinrm) (38.0.1)
Requirement already satisfied: cffi>=1.12 in ./.venv/lib/python3.8/site-packages (from cryptography>=1.3->requests-ntlm>=1.1.0->pywinrm) (1.15.1)
Requirement already satisfied: pycparser in ./.venv/lib/python3.8/site-packages (from cffi>=1.12->cryptography>=1.3->requests-ntlm>=1.1.0->pywinrm) (2.21)
Installing collected packages: xmltodict, urllib3, six, ntlm-auth, idna, charset-normalizer, certifi, requests, requests-ntlm, pywinrm
Successfully installed certifi-2022.9.24 charset-normalizer-2.1.1 idna-3.4 ntlm-auth-1.5.0 pywinrm-0.4.3 requests-2.28.1 requests-ntlm-1.1.0 six-1.16.0 urllib3-1.26.12 xmltodict-0.13.0

6. Pythonパッケージインストール後の確認

インストール後、pip listでパッケージが表示されることを確認しておこう。

(.venv)# pip list
Package            Version
------------------ ---------
ansible            6.5.0
ansible-core       2.13.5
certifi            2022.9.24
cffi               1.15.1
charset-normalizer 2.1.1
cryptography       38.0.1
idna               3.4
Jinja2             3.1.2
MarkupSafe         2.1.1
ntlm-auth          1.5.0
packaging          21.3
pip                22.3
pycparser          2.21
pyparsing          3.0.9
pywinrm            0.4.3
PyYAML             6.0
requests           2.28.1
requests-ntlm      1.1.0
resolvelib         0.8.1
setuptools         41.6.0
six                1.16.0
urllib3            1.26.12
xmltodict          0.13.0

Ansibleも問題なく2.13.5がインストールできていることが確認できる。

(.venv)# ansible --version
ansible [core 2.13.5]
  config file = /root/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /root/.venv/lib64/python3.8/site-packages/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /root/.venv/bin/ansible
  python version = 3.8.12 (default, Apr 21 2022, 07:55:08) [GCC 8.5.0 20210514 (Red Hat 8.5.0-10)]
  jinja version = 3.1.2
  libyaml = True

なお、Pythonの仮想環境の場合、ansibleansible-playbookの配置場所は、インストールディレクトリは以下の/binとなる。環境変数でパスが設定されているため、ここに配置されたコマンドは特にPythonの仮想環境であることを意識することなくコマンド実行することができる。

(.venv)# which ansible
/root/.venv/bin/ansible
(.venv)# which ansible-playbook
/root/.venv/bin/ansible-playbook

Pythonの仮想環境にてAnsibleコントロールノードから処理を実行

1. ansibleコマンドでpingモジュールを実行

それでは実際にAnsibleを実行してみよう。まずはLinuxサーバに対して定番のpingモジュールを実行してみる。

Ansible実行前にインベントリファイルとしてhostsというファイル名でファイルを作成しておこう。

hosts

(.venv)# cat hosts
[linux_servers]
t1193alma ansible_host=192.168.11.193

[windows_servers]
t1194w219 ansible_host=192.168.11.194

[windows_servers:vars]
ansible_user=ansibleuser
ansible_password=[ansibleuserのパスワード]
ansible_port=5986
ansible_connection=winrm
ansible_winrm_server_cert_validation=ignore

ansibleコマンドにてpingモジュールを実行してみると、問題なく"ping": "pong"と表示された。

(.venv)# ansible -i hosts -u ansibleuser -m ping t1193alma --ask-pass
SSH password:
t1193alma | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false,
    "ping": "pong"
}

2. ansibleコマンドでwin_pingモジュールを実行

同様に、win_pingモジュールを実行してみると、こちらも問題なく"ping": "pong"と表示された。

(.venv)# ansible -i hosts -m win_ping t1194w219
t1194w219 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

3. ansible-playbookコマンドでPlaybookを実行

最後にansible-playbookでPlaybookを実行してみよう。Playbookの内容としては、以下のようなwin_pingするだけの簡単なものを作成した。

ping_windows_server.yml

# cat ping_windows_server.yml
---
- name: Setup windows server
  gather_facts: false
  hosts: windows_servers

  tasks:
    - name: Ping windows server
      ansible.windows.win_ping:

    - name: Debug
      ansible.builtin.debug:
        msg: "{{ inventory_hostname }}"

実行結果は以下の通り。問題なく処理が実行できた。

(.venv)# ansible-playbook -i hosts -l t1194w219 ping_windows_server.yml

PLAY [Setup windows server] ****************************************************

TASK [Ping windows server] *****************************************************
ok: [t1194w219]

TASK [Debug] *******************************************************************
ok: [t1194w219] => {
    "msg": "t1194w219"
}

PLAY RECAP *********************************************************************
t1194w219                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Pythonの仮想環境のAnsibleコントロールノードをアンインストール

1. Pythonの仮想環境を無効化

Pythonの仮想環境を無効化する場合は、deactivateコマンドを用いる。実行すると、プロンプトが通常の状態に戻る。

(.venv) [root@localhost ~]# deactivate
[root@localhost ~]#

2. Pythonの仮想環境をアンインストール

Pythonの仮想環境のアンインストールは、単純に作成したディレクトリ(今回の場合であれば.venv)を削除すればよい。

# rm -rf .venv/

以上で、オフライン環境のPythonの仮想環境にAnsibleコントロールノードを構築する手順は完了となる。

Pythonの仮想環境を用いることで、既存の環境への影響を極力抑えることができ、不要となればディレクトリを削除するだけで済む。そのため、一時的にAnsibleで処理を実行したい時などに利用することができる。

参考

人気の投稿