2023年7月29日土曜日

Ansible Lintの最後に約2分の待ち時間が発生する問題

先日、Ansibleを6.0.0から8.1.0へバージョンアップした。その際に、Ansible Lintのバージョンも新しくなった(6.3.0 -> 6.17.2)。

バージョンアップしたところ、Ansible Lintの処理が想定以上に長期化してしまう問題が発生した。具体的には、Ansible Lintの処理完了後の最後のメッセージ表示がされるまでに、約2分の待ち時間が発生するようになってしまった。

$ ansible-lint

~(中略)~

WARNING  /usr/local/lib/python3.9/site-packages/jmespath/lexer.py:169 PendingDeprecationWarning deprecated string literal syntax
-- ★この間で2分ほど待機がある --
Passed: 0 failure(s), 0 warning(s) on 57 files. Last profile that met the validation criteria was 'production'.

本記事では、この事象を解決する方法を記載する。

環境

環境は以下の通り。

  • OS : AlmaLinux 8.5
  • Ansible : 8.1.0 [core 2.15.1]
  • Ansible Lint : 6.17.2

Ansible Lintのバージョンは以下コマンドで確認している。

$ ansible-lint --version
ansible-lint 6.17.2 using ansible-core:2.15.1 ansible-compat:4.1.2 ruamel-yaml:None ruamel-yaml-clib:None

解決方法

結論から言うと、以下の通り--offlineオプションを付与することで解決できる。

$ ansible-lint --offline

調査内容詳細

ここからは参考情報となるので、興味のある方のみ確認いただきたい。

今回の事象調査のため、ansible-lintコマンドに-vvオプションを付与したうえで詳細な実行結果を確認した。すると、Ansible Lintで時間を要するパターンにおいては以下のログが出力されており、インターネット接続のタイムアウト待ちの時間によって処理が長期化していることを確認した。

DEBUG    Unable to fetch latest version from https://api.github.com/repos/ansible/ansible-lint/releases/latest due to: <urlopen error [Errno 110] Connection timed out>

どうやら、GitHubに最新の情報取得を行おうと試みているようだ。そこで、ansible-lintコマンドのヘルプから--offlineオプションがあることを確認し、付与することで上記動作が発生しないようにした。

以下に、参考情報として--offlineオプションの有無における実行結果を記載する。

--offlineオプションなし

$ ansible-lint -vv

~(中略)~

Read documentation for instructions on how to ignore specific rule violations.

DEBUG    Determined rule-profile order: {'internal-error': (0, 'min'), 'load-failure': (1, 'min'), 'parser-error': (2, 'min'), 'syntax-check': (3, 'min'), 'command-instead-of-module': (4, 'basic'), 'command-instead-of-shell': (5, 'basic'), 'deprecated-bare-vars': (6, 'basic'), 'deprecated-local-action': (7, 'basic'), 'deprecated-module': (8, 'basic'), 'inline-env-var': (9, 'basic'), 'key-order': (10, 'basic'), 'literal-compare': (11, 'basic'), 'jinja': (12, 'basic'), 'no-free-form': (13, 'basic'), 'no-jinja-when': (14, 'basic'), 'no-tabs': (15, 'basic'), 'partial-become': (16, 'basic'), 'playbook-extension': (17, 'basic'), 'role-name': (18, 'basic'), 'schema': (19, 'basic'), 'name': (20, 'basic'), 'var-naming': (21, 'basic'), 'yaml': (22, 'basic'), 'name': (23, 'moderate'), 'name': (24, 'moderate'), 'name': (25, 'moderate'), 'spell-var-name': (26, 'moderate'), 'avoid-implicit': (27, 'safety'), 'latest': (28, 'safety'), 'package-latest': (29, 'safety'), 'risky-file-permissions': (30, 'safety'), 'risky-octal': (31, 'safety'), 'risky-shell-pipe': (32, 'safety'), 'galaxy': (33, 'shared'), 'ignore-errors': (34, 'shared'), 'layout': (35, 'shared'), 'meta-incorrect': (36, 'shared'), 'meta-no-tags': (37, 'shared'), 'meta-video-links': (38, 'shared'), 'meta-version': (39, 'shared'), 'meta-runtime': (40, 'shared'), 'no-changed-when': (41, 'shared'), 'no-changelog': (42, 'shared'), 'no-handler': (43, 'shared'), 'no-relative-paths': (44, 'shared'), 'max-block-depth': (45, 'shared'), 'max-tasks': (46, 'shared'), 'unsafe-loop': (47, 'shared'), 'avoid-dot-notation': (48, 'production'), 'sanity': (49, 'production'), 'fqcn': (50, 'production'), 'import-task-no-when': (51, 'production'), 'meta-no-dependencies': (52, 'production'), 'single-entry-point': (53, 'production'), 'use-loop': (54, 'production')}
                Rule Violation Summary
 count tag               profile rule associated tags
    12 yaml[empty-lines] basic   formatting, yaml
    23 yaml[indentation] basic   formatting, yaml

DEBUG    Unable to fetch latest version from https://api.github.com/repos/ansible/ansible-lint/releases/latest due to: <urlopen error [Errno 110] Connection timed out>
Failed: 35 failure(s), 0 warning(s) on 130 files. Last profile that met the validation criteria was 'min'.

--offlineオプションあり

$ ansible-lint --offline -vv

~(中略)~

Read documentation for instructions on how to ignore specific rule violations.

DEBUG    Determined rule-profile order: {'internal-error': (0, 'min'), 'load-failure': (1, 'min'), 'parser-error': (2, 'min'), 'syntax-check': (3, 'min'), 'command-instead-of-module': (4, 'basic'), 'command-instead-of-shell': (5, 'basic'), 'deprecated-bare-vars': (6, 'basic'), 'deprecated-local-action': (7, 'basic'), 'deprecated-module': (8, 'basic'), 'inline-env-var': (9, 'basic'), 'key-order': (10, 'basic'), 'literal-compare': (11, 'basic'), 'jinja': (12, 'basic'), 'no-free-form': (13, 'basic'), 'no-jinja-when': (14, 'basic'), 'no-tabs': (15, 'basic'), 'partial-become': (16, 'basic'), 'playbook-extension': (17, 'basic'), 'role-name': (18, 'basic'), 'schema': (19, 'basic'), 'name': (20, 'basic'), 'var-naming': (21, 'basic'), 'yaml': (22, 'basic'), 'name': (23, 'moderate'), 'name': (24, 'moderate'), 'name': (25, 'moderate'), 'spell-var-name': (26, 'moderate'), 'avoid-implicit': (27, 'safety'), 'latest': (28, 'safety'), 'package-latest': (29, 'safety'), 'risky-file-permissions': (30, 'safety'), 'risky-octal': (31, 'safety'), 'risky-shell-pipe': (32, 'safety'), 'galaxy': (33, 'shared'), 'ignore-errors': (34, 'shared'), 'layout': (35, 'shared'), 'meta-incorrect': (36, 'shared'), 'meta-no-tags': (37, 'shared'), 'meta-video-links': (38, 'shared'), 'meta-version': (39, 'shared'), 'meta-runtime': (40, 'shared'), 'no-changed-when': (41, 'shared'), 'no-changelog': (42, 'shared'), 'no-handler': (43, 'shared'), 'no-relative-paths': (44, 'shared'), 'max-block-depth': (45, 'shared'), 'max-tasks': (46, 'shared'), 'unsafe-loop': (47, 'shared'), 'avoid-dot-notation': (48, 'production'), 'sanity': (49, 'production'), 'fqcn': (50, 'production'), 'import-task-no-when': (51, 'production'), 'meta-no-dependencies': (52, 'production'), 'single-entry-point': (53, 'production'), 'use-loop': (54, 'production')}
                Rule Violation Summary
 count tag               profile rule associated tags
    12 yaml[empty-lines] basic   formatting, yaml
    23 yaml[indentation] basic   formatting, yaml

Failed: 35 failure(s), 0 warning(s) on 130 files. Last profile that met the validation criteria was 'min'.

以上。

2023年7月22日土曜日

kubectl versionコマンド実行時に"deprecated"の警告メッセージを出力させない方法

Kubernetes環境のバージョンは、kubectl versionコマンドを用いることで確認することができる。しかし、Kubernetes v1.27.3の環境で試したところ、以下の通りWARNING: This version information is deprecatedの警告メッセージが表示される。

# kubectl version
WARNING: This version information is deprecated and will be replaced with the output from kubectl version --short.  Use --output=yaml|json to get the full version.
Client Version: version.Info{Major:"1", Minor:"27", GitVersion:"v1.27.3", GitCommit:"25b4e43193bcda6c7328a6d147b1fb73a33f1598", GitTreeState:"clean", BuildDate:"2023-06-14T09:53:42Z", GoVersion:"go1.20.5", Compiler:"gc", Platform:"linux/amd64"}
Kustomize Version: v5.0.1
Server Version: version.Info{Major:"1", Minor:"27", GitVersion:"v1.27.3", GitCommit:"25b4e43193bcda6c7328a6d147b1fb73a33f1598", GitTreeState:"clean", BuildDate:"2023-06-14T09:47:40Z", GoVersion:"go1.20.5", Compiler:"gc", Platform:"linux/amd64"}

警告メッセージにkubectl version --shortとあるので、ためしにそれを実行すると、今度はFlag --short has been deprecatedという警告が出てきた。このメッセージは、将来的にオプションを付けなくてもデフォルト表示になる旨を示しており無視しても問題なさそうだが、気にはなってしまう。。

# kubectl version --short
Flag --short has been deprecated, and will be removed in the future. The --short output will become the default.
Client Version: v1.27.3
Kustomize Version: v5.0.1
Server Version: v1.27.3

本記事では、kubectl versionコマンドを実行する際にdeprecatedの警告メッセージを表示させないようにする方法を記載する。

環境

  • Kubernetes v1.27.3

解決方法

警告メッセージを表示させないようにするには、以下の通りkubectl versionコマンドに--output=yamlまたは--output=jsonのオプションを付与すればよい。それぞれ、出力形式をYAMLまたはJSONに整形し、詳細情報を表示するオプションとなる(オプションは-o=yamlのように省略して記載可能)。

以下に出力例を記載する。

YAML形式

# kubectl version --output=yaml
clientVersion:
  buildDate: "2023-06-14T09:53:42Z"
  compiler: gc
  gitCommit: 25b4e43193bcda6c7328a6d147b1fb73a33f1598
  gitTreeState: clean
  gitVersion: v1.27.3
  goVersion: go1.20.5
  major: "1"
  minor: "27"
  platform: linux/amd64
kustomizeVersion: v5.0.1
serverVersion:
  buildDate: "2023-06-14T09:47:40Z"
  compiler: gc
  gitCommit: 25b4e43193bcda6c7328a6d147b1fb73a33f1598
  gitTreeState: clean
  gitVersion: v1.27.3
  goVersion: go1.20.5
  major: "1"
  minor: "27"
  platform: linux/amd64

JSON形式

# kubectl version --output=json
{
  "clientVersion": {
    "major": "1",
    "minor": "27",
    "gitVersion": "v1.27.3",
    "gitCommit": "25b4e43193bcda6c7328a6d147b1fb73a33f1598",
    "gitTreeState": "clean",
    "buildDate": "2023-06-14T09:53:42Z",
    "goVersion": "go1.20.5",
    "compiler": "gc",
    "platform": "linux/amd64"
  },
  "kustomizeVersion": "v5.0.1",
  "serverVersion": {
    "major": "1",
    "minor": "27",
    "gitVersion": "v1.27.3",
    "gitCommit": "25b4e43193bcda6c7328a6d147b1fb73a33f1598",
    "gitTreeState": "clean",
    "buildDate": "2023-06-14T09:47:40Z",
    "goVersion": "go1.20.5",
    "compiler": "gc",
    "platform": "linux/amd64"
  }
}

以上。

2023年7月15日土曜日

VS Codeでgit push時に発生する「Missing or invalid credentials.」のエラー解消方法

本記事では、VS Codeでgit push時に発生する「Missing or invalid credentials.」のエラーの解消方法を記載する。

環境

  • VS Code : 1.76.1
  • Remote - SSH : v0.102.0
  • 接続先Linux OS : AlmaLinux 8.5

事象

VS CodeでRemote - SSHの拡張機能を用いてLinux OSにSSH接続した状態でgit pushすると以下のような「Missing or invalid credentials.」のエラーで失敗することがある。

# git push
Missing or invalid credentials.
Error: connect ECONNREFUSED /run/user/0/vscode-git-d76c335e68.sock
    at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1157:16) {
  errno: -111,
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '/run/user/0/vscode-git-d76c335e68.sock'
}
Missing or invalid credentials.
Error: connect ECONNREFUSED /run/user/0/vscode-git-d76c335e68.sock
    at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1157:16) {
  errno: -111,
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '/run/user/0/vscode-git-d76c335e68.sock'
}
remote: HTTP Basic: Access denied. The provided password or token is incorrect or your account has 2FA enabled and you must use a personal access token instead of a password. See http://t1026gitl.test.local/help/topics/git/troubleshooting_git#error-on-git-fetch-http-basic-access-denied
fatal: Authentication failed for 'http://t1026gitl.test.local/ansible/test.git/'

解消方法

本事象は、環境変数が悪さをするようだ。

exportコマンドで環境変数を確認すると、GIT_ASKPASSという環境変数において何やらVS Codeのシェルが指定されていることがわかる。おそらく、このシェルを介してVS Codeからgit実行時のユーザー名・パスワード情報の入力をできるようにしていると想定されるが、これがうまく動作しないことが原因となる。

# export | grep GIT_ASKPASS
declare -x GIT_ASKPASS="/root/.vscode-server/bin/5e80xxxxfcb6ba4c2d23712967dxxxx089da575b/extensions/git/dist/askpass.sh"

というわけで、環境変数GIT_ASKPASSunsetコマンドで解除する。

# unset GIT_ASKPASS

git pushするとユーザー名とパスワードを求められるので、正しい情報を入力すれば、git pushに成功するようになる。

# git push
Username for 'http://t1026gitl.test.local': tadmin
Password for 'http://tadmin@t1026gitl.test.local': 
Enumerating objects: 37, done.
Counting objects: 100% (37/37), done.
Delta compression using up to 2 threads
Compressing objects: 100% (22/22), done.
Writing objects: 100% (22/22), 2.07 KiB | 2.07 MiB/s, done.
Total 22 (delta 18), reused 0 (delta 0), pack-reused 0
To http://t1026gitl.test.local/ansible/test.git
   f9860d8..60d4beb  main -> main

以上で、VS Codeでgit push時に発生する「Missing or invalid credentials.」のエラーの解消方法の手順は完了となる。

2023年7月8日土曜日

Kubernetesバージョンアップ手順

Kubernetesはバージョンアップ頻度が高く、おおよそ4か月に1回のペースで新しいマイナーバージョンがリリースされている。

バージョン リリース日
1.27 2023-04-11
1.26 2022-12-09
1.25 2022-08-23

サポートが有効なバージョンは最新の3世代となることから、結果として12ヶ月に1回はバージョンアップし、サポートされる状態を維持する必要がある。

Kubernetesのバージョンアップは決められた手順に従い実施すればそこまで難しいものではない。本記事では、Kubernetesのバージョンアップ手順を記載する。

環境

以下に各種ソフトウェアのバージョンを記載する。今回はバージョン1.27のパッチバージョンのバージョンアップとなるが、おそらくマイナーバージョン(例えば、1.27 -> 1.28)などでも同様の手順で実施できると想定している。

  • ホストOS : AlmaLinux 8.6
  • Kubernetes:
    • バージョンアップ前 : v1.27.1
    • バージョンアップ後 : v1.27.3

クラスターは3台で構成し、すべてコントロールプレーンのノードとなる。冗長化されたコントロールプレーンのKubernetesクラスターの構築手順は以下記事を参照いただきたい。

以下に、本記事で用いるKubernetes環境の構成概要図と、バージョンアップ手順の概要を記載する。

Kubernetesバージョンアップ手順

1. kubeadmバージョンアップ

バージョンアップ前のバージョン確認をしておく。kubeadmやノードのバージョンは、v1.27.1となっていることがわかる。

# kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"27", GitVersion:"v1.27.1", GitCommit:"4c9411232e10168d7b050c49a1b59f6df9d7ea4b", GitTreeState:"clean", BuildDate:"2023-04-14T13:20:04Z", GoVersion:"go1.20.3", Compiler:"gc", Platform:"linux/amd64"}

# kubectl get node
NAME        STATUS   ROLES           AGE   VERSION
t3051kube   Ready    control-plane   25d   v1.27.1
t3052kube   Ready    control-plane   25d   v1.27.1
t3053kube   Ready    control-plane   25d   v1.27.1

kubeadmdnfコマンドでバージョンを指定することで、特定のバージョンへバージョンアップすることができる。

# dnf install kubeadm-1.27.3-0 --disableexcludes=kubernetes -y
メタデータの期限切れの最終確認: 0:01:42 時間前の 2023年06月18日 07時33分08秒 に実施しました。
依存関係が解決しました。
====================================================================================================================================================
 パッケージ                        アーキテクチャー                 バージョン                           リポジトリー                         サイズ
====================================================================================================================================================
アップグレード:
 kubeadm                           x86_64                           1.27.3-0                             kubernetes                            11 M

トランザクションの概要
====================================================================================================================================================
アップグレード  1 パッケージ

ダウンロードサイズの合計: 11 M

~(以下略)~

バージョンアップ後、kubeadmがバージョンアップされていることを確認しよう。今回であれば、v1.27.1 -> v1.27.3になっていることが確認できる。

# kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"27", GitVersion:"v1.27.3", GitCommit:"25b4e43193bcda6c7328a6d147b1fb73a33f1598", GitTreeState:"clean", BuildDate:"2023-06-14T09:52:26Z", GoVersion:"go1.20.5", Compiler:"gc", Platform:"linux/amd64"}

2. アップグレードプランの確認

アップグレードプランを確認する。ここで、現在のKubernetesクラスターの状態が確認され、最終的にバージョンアップに必要なコマンドが表示される。

# kubeadm upgrade plan
[upgrade/config] Making sure the configuration is correct:
[upgrade/config] Reading configuration from the cluster...
[upgrade/config] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[preflight] Running pre-flight checks.
[upgrade] Running cluster health checks
[upgrade] Fetching available versions to upgrade to
[upgrade/versions] Cluster version: v1.27.2
[upgrade/versions] kubeadm version: v1.27.3
[upgrade/versions] Target version: v1.27.3
[upgrade/versions] Latest version in the v1.27 series: v1.27.3

Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
COMPONENT   CURRENT       TARGET
kubelet     3 x v1.27.1   v1.27.3

Upgrade to the latest version in the v1.27 series:

COMPONENT                 CURRENT   TARGET
kube-apiserver            v1.27.2   v1.27.3
kube-controller-manager   v1.27.2   v1.27.3
kube-scheduler            v1.27.2   v1.27.3
kube-proxy                v1.27.2   v1.27.3
CoreDNS                   v1.10.1   v1.10.1
etcd                      3.5.7-0   3.5.7-0

You can now apply the upgrade by executing the following command:

        kubeadm upgrade apply v1.27.3

_____________________________________________________________________


The table below shows the current state of component configs as understood by this version of kubeadm.
Configs that have a "yes" mark in the "MANUAL UPGRADE REQUIRED" column require manual config upgrade or
resetting to kubeadm defaults before a successful upgrade can be performed. The version to manually
upgrade to is denoted in the "PREFERRED VERSION" column.

API GROUP                 CURRENT VERSION   PREFERRED VERSION   MANUAL UPGRADE REQUIRED
kubeproxy.config.k8s.io   v1alpha1          v1alpha1            no
kubelet.config.k8s.io     v1beta1           v1beta1             no
_____________________________________________________________________

3. Kubernetesクラスターのバージョンアップ (1台目)

アップグレードプランの確認で出力されたkubeadm upgrade apply [ターゲットバージョン]コマンドを用いてKubernetesクラスターのバージョンアップを行う。この作業はコントロールプレーンの1台で実行する。

# kubeadm upgrade apply v1.27.3
[upgrade/config] Making sure the configuration is correct:
[upgrade/config] Reading configuration from the cluster...

~(中略)~

[upgrade/successful] SUCCESS! Your cluster was upgraded to "v1.27.3". Enjoy!

[upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so.

4. Kubernetesクラスターのバージョンアップ (2台目以降)

コントロールプレーンが冗長化されている場合は、2台目以降のすべてのコントロールプレーンのノードにて、kubeadm upgrade nodeコマンドを実行する。

# kubeadm upgrade node
[upgrade] Reading configuration from the cluster...
[upgrade] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
W0618 07:46:01.123220 3723323 images.go:80] could not find officially supported version of etcd for Kubernetes v1.27.3, falling back to the nearest etcd version (3.5.7-0)
W0618 07:46:27.546881 3723323 checks.go:835] detected that the sandbox image "registry.k8s.io/pause:3.6" of the container runtime is inconsistent with that used by kubeadm. It is recommended that using "registry.k8s.io/pause:3.9" as the CRI sandbox image.
[upgrade] Upgrading your Static Pod-hosted control plane instance to version "v1.27.3"...

~(中略)~

[upgrade] The configuration for this node was successfully updated!
[upgrade] Now you should go ahead and upgrade the kubelet package using your package manager.

5. drain実行 (Podの退避・Podの配置の禁止)

Kubernetesクラスターのバージョンアップが完了したら、各ノードのkubelet及びkubectlのバージョンアップを行う。

一時的にkubeletの再起動が発生することから、バージョンアップ対象ノードからPodを退避(drain)したのち、Podの配置を禁止(cordon)する。

# kubectl drain t3051kube --ignore-daemonsets
node/t3051kube cordoned
Warning: ignoring DaemonSet-managed Pods: kube-flannel/kube-flannel-ds-x9mzn, kube-system/kube-proxy-6q4qn

~(中略)~

node/t3051kube drained

drainされると、ノードのステータスがSchedulingDisabledとなる。

# kubectl get node
NAME        STATUS                     ROLES           AGE   VERSION
t3051kube   Ready,SchedulingDisabled   control-plane   25d   v1.27.1
t3052kube   Ready                      control-plane   25d   v1.27.1
t3053kube   Ready                      control-plane   25d   v1.27.1

6. kubelet及びkubectlのバージョンアップ

kubelet及びkubectldnfコマンドでバージョンを指定することで、特定のバージョンへバージョンアップすることができる。

# dnf install kubelet-1.27.3-0 kubectl-1.27.3-0 --disableexcludes=kubernetes -y
メタデータの期限切れの最終確認: 0:28:16 時間前の 2023年06月18日 07時33分08秒 に実施しました。
依存関係が解決しました。
====================================================================================================================================================
 パッケージ                        アーキテクチャー                 バージョン                           リポジトリー                         サイズ
====================================================================================================================================================
アップグレード:
 kubectl                           x86_64                           1.27.3-0                             kubernetes                            11 M
 kubelet                           x86_64                           1.27.3-0                             kubernetes                            20 M

トランザクションの概要
====================================================================================================================================================
アップグレード  2 パッケージ

ダウンロードサイズの合計: 31 M

~(以下略)~

7. kubelet再起動

kubeletのバージョンアップ後、再起動を行う。

# systemctl daemon-reload
# systemctl restart kubelet

ノードの状態を確認すると、バージョンがv1.27.1 -> v1.27.3となっていることがわかる。

# kubectl get node
NAME        STATUS                     ROLES           AGE   VERSION
t3051kube   Ready,SchedulingDisabled   control-plane   25d   v1.27.3
t3052kube   Ready                      control-plane   25d   v1.27.1
t3053kube   Ready                      control-plane   25d   v1.27.1

8. uncordon実行

バージョンアップが完了したので、対象ノードのcordon状態を解消するため、uncordonを実行する。

# kubectl uncordon t3051kube

最終的にノードがバージョンアップされた状態でReadyとなった。

# kubectl get node
NAME        STATUS   ROLES           AGE   VERSION
t3051kube   Ready    control-plane   25d   v1.27.3
t3052kube   Ready    control-plane   25d   v1.27.1
t3053kube   Ready    control-plane   25d   v1.27.1

9. 手順5~8を残りのノードに対して繰り返す

残りのノードに対してもdrain、kubeletバージョンアップ、uncordonを繰り返しながらローリングアップデートを実行する。

以下は2台目の実行例となる。

# kubectl drain t3052kube --ignore-daemonsets
node/t3051kube cordoned

# dnf install kubelet-1.27.3-0 kubectl-1.27.3-0 --disableexcludes=kubernetes -y
# systemctl daemon-reload
# systemctl restart kubelet

# kubectl uncordon t3052kube

# kubectl get node
NAME        STATUS     ROLES           AGE   VERSION
t3051kube   Ready      control-plane   25d   v1.27.3
t3052kube   NotReady   control-plane   25d   v1.27.3
t3053kube   Ready      control-plane   25d   v1.27.1

以上で、Kubernetesのバージョンアップ手順は完了となる。

参考

2023年7月2日日曜日

NGINXの負荷分散装置(ロードバランサ)をPacemakerで冗長化する

先日、NGINXを使って負荷分散装置(ロードバランサ)を構築してみた。

2台のサーバに対して負荷分散して通信できることで、リソースを分散させるだけでなく冗長化も図ることができたが、肝心の負荷分散装置であるNGINX自体がシングルポイントとなっているため、可用性の観点から不十分である。

しかし、OSSのNGINXではNGINXによる冗長化機能はないため、もし冗長化したい場合は別の手法を検討する必要がある。そこで、以前から本ブログで紹介したことがある「Pacemaker+Corosync」を使って、クラスタ構成による冗長化を図ることにした。

今回はPacemaker+Corosyncを使ってNGINXをクラスタ化し冗長構成された負荷分散装置(ロードバランサ)を構築する。

環境

環境としては以下の通りAlmaLinuxを利用したが、そのほかのRed Hat系のディストリビューションであれば、ほぼ同様の手順で構築できるはずだ。

  • AlmaLinux 8.5 及び AlmaLinux 9.2
  • NGINX 1.14.1

負荷分散装置の構成は以下の通りとする。クライアントからの通信と負荷分散対象サーバが同一のインタフェースとなる「ワンアーム」構成となる。なお、NGINXでは、通信は必ずSource NATされるため、ワンアーム構成としたとしても特別な設定は不要となる。

Pacemaker+CorosyncによるNGINX冗長化手順

1. 2台のサーバでNGINXを構築

Pacemaker+Corosyncでクラスタを構成する前に、事前にクラスタ対象サーバでNGINXを負荷分散装置として動作するよう構築しておこう。再掲となるが、手順は以下を参照してほしい。

2. Pacemaker+Corosyncを構築

Pacemaker+Corosyncの構築手順は、以前別記事にて記載している。こちらを参考に、クラスタの起動までできるように構築する。

補足として、AlmaLinux 8.5においては、Pacemaker+Corosyncのインストールに必要なリポジトリがHighAvailabilityではなくhaになっている。

# dnf repolist all
repo id                    repo の名前                                    状態
~(中略)~
ha                         AlmaLinux 8 - HighAvailability                 無効化
ha-debuginfo               AlmaLinux 8 - HighAvailability debuginfo       無効化
ha-source                  AlmaLinux 8 - HighAvailability Source          無効化
~(以下略)~

したがって、dnfによるインストール実施時に、リポジトリを以下のように指定して対応しよう。なお、AlmaLinux 9.2ではリポジトリ名がhighavailability(全部小文字)になっていたので、OSバージョンに合わせて適切なリポジトリを選択しよう。

# dnf --enablerepo=ha install pacemaker pcs fence-agents-all pcp-zeroconf -y

3. クラスタリソース及び制約設定

Pacemaker+Corosyncのインストールが終わったら、以下の通りクラスタリソースと制約の設定を行う。

リソース種類 リソース名 設定値
VIP rs-vip-33 ens192のインタフェースに対して192.168.33.23/24のIPアドレスを設定する。
NGINX rs-systemd-nginx NGINXをsystemdにて起動・停止する。
Ping rs-ping-33 ゲートウェイに対して各サーバからPingを実行し、Ping疎通ができないサーバではリソースを起動できないよう制約 (constraint) を設定する。
# pcs resource create rs-vip-33 ocf:heartbeat:IPaddr2 ip=192.168.33.23 cidr_netmask=24 nic=ens192 --group rg-01
# pcs resource create rs-systemd-nginx systemd:nginx --group rg-01

# pcs resource create rs-ping-33 ocf:pacemaker:ping dampen=5s multiplier=1000 host_list=192.168.33.31
# pcs resource clone rs-ping-33
# pcs constraint location rg-01 rule score=-INFINITY pingd lt 1 or not_defined pingd

最終的なリソース及び制約の設定は以下の通り。

# pcs resource show --full
Warning: This command is deprecated and will be removed. Please use 'pcs resource config' instead.
 Group: rg-01
  Resource: rs-vip-33 (class=ocf provider=heartbeat type=IPaddr2)
   Attributes: cidr_netmask=24 ip=192.168.33.23 nic=ens192
   Operations: monitor interval=10s timeout=20s (rs-vip-33-monitor-interval-10s)
               start interval=0s timeout=20s (rs-vip-33-start-interval-0s)
               stop interval=0s timeout=20s (rs-vip-33-stop-interval-0s)
  Resource: rs-systemd-nginx (class=systemd type=nginx)
   Operations: monitor interval=60 timeout=100 (rs-systemd-nginx-monitor-interval-60)
               start interval=0s timeout=100 (rs-systemd-nginx-start-interval-0s)
               stop interval=0s timeout=100 (rs-systemd-nginx-stop-interval-0s)
 Clone: rs-ping-33-clone
  Resource: rs-ping-33 (class=ocf provider=pacemaker type=ping)
   Attributes: dampen=5s host_list=192.168.33.31 multiplier=1000
   Operations: monitor interval=10s timeout=60s (rs-ping-33-monitor-interval-10s)
               start interval=0s timeout=60s (rs-ping-33-start-interval-0s)
               stop interval=0s timeout=20s (rs-ping-33-stop-interval-0s)

# pcs constraint
Location Constraints:
  Resource: rg-01
    Constraint: location-rg-01
      Rule: boolean-op=or score=-INFINITY
        Expression: pingd lt 1
        Expression: not_defined pingd
Ordering Constraints:
Colocation Constraints:
Ticket Constraints:

4. 動作確認

クラスタリソースが稼働しているサーバをシャットダウンした際に、もう1台のサーバにフェイルオーバーすることを確認する。

フェイルオーバー前の状態は以下の通り。

# pcs status
Cluster name: clst-01
Cluster Summary:
  * Stack: corosync
  * Current DC: t3041ngnx (version 2.1.0-8.el8-7c3f660707) - partition with quorum
  * Last updated: Sun Apr 24 11:47:32 2022
  * Last change:  Sat Apr 23 08:50:12 2022 by root via cibadmin on t3041ngnx
  * 2 nodes configured
  * 4 resource instances configured

Node List:
  * Online: [ t3041ngnx t3042ngnx ]

Full List of Resources:
  * Resource Group: rg-01:
    * rs-vip-33 (ocf::heartbeat:IPaddr2):        Started t3041ngnx
    * rs-systemd-nginx  (systemd:nginx):         Started t3041ngnx
  * Clone Set: rs-ping-33-clone [rs-ping-33]:
    * Started: [ t3041ngnx t3042ngnx ]

Daemon Status:
  corosync: active/disabled
  pacemaker: active/disabled
  pcsd: active/enabled

稼働系のサーバをシャットダウンすると、以下の通り残りのサーバでクラスタリソースが再起動されていることがわかる。

# pcs status
Cluster name: clst-01
Cluster Summary:
  * Stack: corosync
  * Current DC: t3042ngnx (version 2.1.0-8.el8-7c3f660707) - partition with quorum
  * Last updated: Sun Apr 24 11:48:15 2022
  * Last change:  Sat Apr 23 08:50:12 2022 by root via cibadmin on t3041ngnx
  * 2 nodes configured
  * 4 resource instances configured

Node List:
  * Online: [ t3042ngnx ]
  * OFFLINE: [ t3041ngnx ]

Full List of Resources:
  * Resource Group: rg-01:
    * rs-vip-33 (ocf::heartbeat:IPaddr2):        Started t3042ngnx
    * rs-systemd-nginx  (systemd:nginx):         Started t3042ngnx
  * Clone Set: rs-ping-33-clone [rs-ping-33]:
    * Started: [ t3042ngnx ]
    * Stopped: [ t3041ngnx ]

Daemon Status:
  corosync: active/disabled
  pacemaker: active/disabled
  pcsd: active/enabled

以上で、Pacemaker+Corosyncを使ってNGINXをクラスタ化し冗長構成された負荷分散装置を構築する手順は完了となる。

更新履歴

  • 2022/6/11 新規作成
  • 2023/7/2 AlmaLinux 9.2の記載を追記

2023年7月1日土曜日

Ansibleを6.0.0から8.1.0にバージョンアップする手順

自宅ではAnsibleを用いて各種作業の自動化を進めている。Ansibleのインストール手順は以下に記載している。

上記は、2022年7月にインストールした記事であり、Ansibleのバージョンが6.0.0とかなり古くなっていた。

Ansibleのバージョン情報は、以下URLから確認することができ、Ansible core 2.13に該当するAnsible 6.xはすでにUnmaintained (end of life)となっている。

そこで今回、Ansibleを6.0.0 (core 2.13) から 8.1.0 (core 2.15) へバージョンアップすることにした。

環境

コントロールノードとなるOSは、AlmaLinuxを用いる。ただし、Red Hat系のディストリビューションであるCentOSやRocky Linuxなどでも同様の手順で作業ができるだろう。

  • OS : AlmaLinux 8.5
  • Python : 3.8 -> 3.9
  • Ansible : 6.0.0 -> 8.1.0

Ansibleバージョンアップ手順

1. pipを最新バージョンに更新

Ansibleインストール前に、pip自体をバージョンアップする。

# python3 -m pip install --upgrade pip

2. インストール可能なAnsibleのバージョンを確認

pipを使ってインストール可能なバージョンを確認してみる。pip install [インストールモジュール名]==のように対象バージョンを省略して記載すると、インストール可能なバージョンの一覧が表示される。

以下の通り、Python 3.8の場合は、Ansible 6.xまでしか表示されない。そのため、以降の手順でPython 3.9のインストールを行うことにする。

# python3 -m pip install --upgrade ansible==
~(中略)~
ansible== (from versions: (中略) 6.0.0, 6.1.0, 6.2.0,
6.3.0, 6.4.0, 6.5.0, 6.6.0, 6.7.0)
ERROR: No matching distribution found for ansible==

3. Python 3.9をインストール

Ansibleを利用する場合、Pythonも対応するバージョンを使用する必要がある。例えば、最近のバージョンでは以下のバージョン制約がある。

Ansible Python
8.x 3.9-3.11
7.x 3.9-3.11
6.x 3.8-3.10

今回、Ansibleのバージョンは8.1.0となることから、AlmaLinux 8.xでインストール可能なPython 3.9をインストールする。

# dnf install python39 -y

4. 通常使用するPythonの入れ替え

通常利用するPythonをPython 3.6から3.8に変更するため、alternativesを使って、以下の通り設定する。

# ls -l /usr/bin/python3*
lrwxrwxrwx 1 root root   25  7月  1  2022 /usr/bin/python3 -> /etc/alternatives/python3
lrwxrwxrwx 1 root root   31 10月 10  2021 /usr/bin/python3.6 -> /usr/libexec/platform-python3.6
lrwxrwxrwx 1 root root   32 10月 10  2021 /usr/bin/python3.6m -> /usr/libexec/platform-python3.6m
-rwxr-xr-x 1 root root 7760  4月 21  2022 /usr/bin/python3.8
-rwxr-xr-x 1 root root 7768  4月  4 01:41 /usr/bin/python3.9

# alternatives --list
libnssckbi.so.x86_64    auto    /usr/lib64/pkcs11/p11-kit-trust.so
python                  auto    /usr/libexec/no-python
ifup                    auto    /usr/libexec/nm-ifup
cifs-idmap-plugin       auto    /usr/lib64/cifs-utils/cifs_idmap_sss.so
python3                 manual  /usr/bin/python3.8
libwbclient.so.0.15-64  auto    /usr/lib64/samba/wbclient/libwbclient.so.0.15

# alternatives --set python3 /usr/bin/python3.9

# alternatives --list
libnssckbi.so.x86_64    auto    /usr/lib64/pkcs11/p11-kit-trust.so
python                  auto    /usr/libexec/no-python
ifup                    auto    /usr/libexec/nm-ifup
cifs-idmap-plugin       auto    /usr/lib64/cifs-utils/cifs_idmap_sss.so
python3                 manual  /usr/bin/python3.9
libwbclient.so.0.15-64  auto    /usr/lib64/samba/wbclient/libwbclient.so.0.15

5. 再度、インストール可能なAnsibleのバージョンを確認

再度、インストール可能なAnsibleのバージョンを確認する。今度は、8.xのバージョンがインストール可能となっていることがわかる。

# python3 -m pip install --upgrade ansible==
~(中略)~
ansible== (from versions: (中略) 6.0.0, 6.1.0, 6.2.0,
6.3.0, 6.4.0, 6.5.0, 6.6.0, 6.7.0, 7.0.0a1, 7.0.0a2,
7.0.0b1, 7.0.0rc1, 7.0.0, 7.1.0, 7.2.0, 7.3.0, 7.4.0,
7.5.0, 7.6.0, 7.7.0, 8.0.0a1, 8.0.0a2, 8.0.0a3,
8.0.0b1, 8.0.0rc1, 8.0.0, 8.1.0)
ERROR: No matching distribution found for ansible==

6. Ansibleバージョンアップ

今回は、Ansible 8.1.0のバージョンを指定して、以下の通りAnsibleをインストールする。

# python3 -m pip install ansible==8.1.0

問題なくインストールされたことを以下コマンドで確認する。Ansible 8.1.0がインストールされ、ansibleコマンドの表示バージョンがansible core 2.15となっていることがわかる。

# pip3 list
Package             Version
------------------- -------
ansible             8.1.0
ansible-core        2.15.1
cffi                1.15.1
cryptography        41.0.1
importlib-resources 5.0.7
Jinja2              3.1.2
MarkupSafe          2.1.3
packaging           23.1
pip                 20.2.4
pycparser           2.21
PyYAML              6.0
resolvelib          1.0.1
setuptools          50.3.2

# ansible --version
ansible [core 2.15.1]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python3.9/site-packages/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/local/bin/ansible
  python version = 3.9.16 (main, Apr  3 2023, 12:39:37) [GCC 8.5.0 20210514 (Red Hat 8.5.0-18)] (/usr/bin/python3)
  jinja version = 3.1.2
  libyaml = True

7. Ansible関連のPythonモジュールを追加

最後に、Ansibleを実行する際に必要となるPythonモジュールをインストールする。

私の環境の場合は以下をインストールした。

モジュール 用途
ansible-lint Ansible Lint(構文チェックツール)本体。
jmespath Ansible Lintの構文チェックで利用されるモジュール。
pywinrm Windows操作用モジュール。
pyvmomi vSphere操作用モジュール。
zabbix-api Zabbix操作用モジュール。
passlib パスワードハッシュ用モジュール。
# python3 -m pip install ansible-lint jmespath
# python3 -m pip install pywinrm pyvmomi zabbix-api passlib

以上で、Ansibleを6.0.0 (core 2.13) から 8.1.0 (core 2.15) へバージョンアップする手順は完了となる。

バージョンアップ後もほとんどのPlaybookはそのまま実行させることができたが、Zabbix操作のPlaybookは接続時の指定方法が変更となっており、そのままでは実行できなかった。Ansibleを用いたZabbixの操作方法の最新手順は、以下別記事に記載する。

人気の投稿