0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ansibleが理解できない理由はLinuxにあった【Shell編】第5回:なぜ環境が違うのか(Execution Context)

0
Last updated at Posted at 2026-04-14

📚 連載:Ansibleが理解できない理由はLinuxにあった【Shell編】第5回:なぜ環境が違うのか(Execution Context)

※Shellの仕組みからAnsibleを理解するシリーズです。

① なぜShellを理解しないとAnsibleは使えないのか
② なぜAnsibleで出力が取得できないのか
③ なぜ結果が消えるのか
④ なぜgrepで見つからないのか
⑤ なぜ正規表現で壊れるのか
⑥ なぜ環境が違うのか
⑦ なぜ条件分岐が失敗するのか
⑧ なぜループがうまく動かないのか
⑨ なぜ途中で処理が止まるのか
⑩ なぜ変数が意図通りに展開されないのか
⑪ なぜAnsibleの挙動が読めるようになるのか


🗺️ 初めての方・シリーズの全体像を知りたい方はこちら

本記事は、OSの仕組みからAnsible設計までを繋ぐ連載シリーズの一部です。
「どこから読み始めればいいか」あるいは、「OS/Shell/Ansible編の関係性」 について把握されたい場合は、以下の統合ガイドで整理しています。

Ansibleが理解できない理由はLinuxにあった|統合ガイド


📑 【Shell編】全体のまとめはこちら
Ansibleが理解できない理由はLinuxにあった【Shell編】まとめ


📑 連載の移動
前の記事:【Shell編】第4回 | 次の記事:【Shell編】第6回


📋 目次

  1. 前回の振り返り(第4回)
  2. 逆引き辞典との連動
  3. 問題定義:同じコマンドなのに、なぜ結果が変わるのか
  4. なぜ環境が違うのか:Shellの「ログイン方式」による棲み分け
  5. 観測方法:Ansibleから見える「本当のPATH」を暴く
  6. よくある実務ミス2選(環境編)
  7. まとめ:環境を支配するための「設計の原則」
  8. 次回予告
  9. 連載一覧:Ansibleが理解できない理由はLinuxにあった【Shell編】

※本記事の位置とシリーズ全体の関係を先に確認します。


:map: シリーズ全体構造(学習 × 問題解決)


本シリーズは
「理解(各記事)」と「問題解決(逆引き辞典)」を組み合わせて
スキルを身につける構成になっています。

この図は、どこから学び、どこに進めばよいかを示した“ロードマップ”です。


📍 現在の位置

現在はこの図の「Shell編の第5回」になります。


↑ 目次に戻る


📍 はじめに:この記事のスタンス

前回の第4回では、Ansibleから渡した「文字列」がShellによってどう評価(書き換え)されるかを学びました。

これで
「何を実行するか(コマンドの内容)」 は制御できるようになりました。

しかし、実務ではまだ依然として以下の現象が発生します

  • 「Teratermでログインして叩けば動くコマンドが、Ansibleからだと『command not found』になる」
  • .bashrc に書いた環境変数が、Ansibleのタスク内では空っぽになっている」
  • 「絶対パスで指定すれば動くが、なぜ相対パスやコマンド名だけでは動かないのかが分からない」

これらの原因は、コマンドの書き間違いではありません。

「どこで実行されるか(実行コンテキスト)」
のルールが、手動実行時とAnsible実行時で根本的に異なっていることにあります。


⚠️ 注意事項
この記事は、PATH の通し方を教えるものではありません。

目的はただひとつです。

「手動実行環境とAnsible実行環境の“棲み分け”を理解し、環境を完全に制御すること」

手動実行とAnsible実行の環境差を整理します。


1. 前回の振り返り(第4回)

前回は「文字列がどう解釈されるか(評価)」を扱いました。

しかし、その解釈は

「どの環境(PATHや環境変数)で実行されるか」

によって結果が変わります。


前回は、Shellが実行直前に文字列をスキャンして書き換える「評価」のプロセスを学びました。

今回は、その評価が行われるための「前提条件」である
環境(PATHや環境変数)が、なぜ実行の入り口によって切り替わってしまうのか
を紐解きます。


↑ 目次に戻る


2. 逆引き辞典との連動

具体的なエラー名から原因を特定したい場合は、以下の逆引き辞典を活用してください。

【保存版】Ansibleよくあるエラー一覧と原因まとめ(Shell編)

  • まず「逆引き辞典」で該当ステップを特定する
  • 次に「本編(各連載記事)」で仕組みを理解する

このサイクルが、OS編から続くトラブル解決の最短ルートです。


↑ 目次に戻る


3. 問題定義:同じコマンドなのに、なぜ結果が変わるのか

エンジニアを最も悩ませるのが、この現象です。

【手動(SSHログイン後)】
$ my_command --version
my_command version 1.2.3  <-- 正常に動く

【Ansible(shellモジュール)】
"stderr": "/bin/sh: my_command: command not found" <-- 失敗する

同じサーバーの、同じユーザーで実行しているはずなのに、なぜ結果が変わるのか?

それは、OSにとって
「ログインして操作するあなた」と
「SSH経由でコマンドだけを投げるAnsible」は、全く別の環境設定で起動されるから
です。


↑ 目次に戻る


4. なぜ環境が違うのか:Shellの「ログイン方式」による棲み分け

Shell(bash等)には、起動する際の入り口によって、読み込む設定ファイルを変える仕組みがあります。

これを
「実行コンテキスト(Execution Context:Shellがどの設定・環境で起動されるか)」と呼びます。


💡 技術的裏付け:ログインシェルと非ログインシェルの差

実行形態 分類 読み込まれる設定ファイル(代表例)
手動実行(SSHログイン) Interactive Login Shell /etc/profile, ~/.bash_profile, ~/.bashrc
Ansible (shell/command) Non-Interactive Non-Login Shell (ユーザー設定ファイルは基本的に読み込まれない)

【解説:なぜAnsibleはPATHを忘れるのか】

  1. 手動ログイン時
    Shellは「これから人間が対話的に操作する」と判断し、~/.bash_profile などの設定ファイルを読み込んでPATHを設定します。

  2. Ansible実行時
    AnsibleはSSH経由で「コマンドだけを最短ルートで実行」しようとします。
    この時、Shellは「対話は不要」と判断し、ユーザーがカスタマイズした設定ファイルを読み飛ばします。

結果として、Ansibleから見えるPATH/usr/bin などの最低限のものだけになり、/usr/local/bin~/.local/bin に入れたコマンドは見つからない状態になります。


↑ 目次に戻る


5. 観測方法:Ansibleから見える「本当のPATH」を暴く

「環境が違う」と疑ったら、想像で設定を変える前に
「今のAnsibleが何を見ているか」 を直接確認します。


観測用タスク:envコマンドの実行

- name: Ansibleから見える環境変数をすべて出力する
  shell: env
  register: remote_env

- debug:
    var: remote_env.stdout_lines

この出力結果を、手動でログインして叩いた env の結果と比較してください。
特に以下に注目してください:

  • PATHの長さ(明らかに短い)
  • HOME配下の設定が反映されていない

📑 実機検証について
本記事のテーマである「手動実行とAnsible実行の環境差」については、OS編第2回にて実機検証を行っています。
SSH手動ログイン・Ansible非対話モード・特権昇格(become)・フルパス指定の4パターンで実際の挙動を確認していますので、あわせて参照してください。
【OS編】第2回:Ansibleでcommand not foundになる理由(PATH)「6. 実機検証:Ansible実行環境における環境変数の差異」


↑ 目次に戻る


6. よくある実務ミス2選(環境編)

ミス①:.bashrc への依存

  • 現象:
    インストールしたアプリのパスを ~/.bashrc に追記したが、Ansibleからは無視される。

  • 解決策:
    タスク内で environment キーワードを使用し、明示的にパスを指定する。
    または、実行コマンドを絶対パス(/usr/local/bin/my_command)で記述する。


ミス②:独自環境変数の消失

  • 現象:
    export APP_ENV=production をプロファイルに書いたのに、Ansibleのタスクで $APP_ENV が空になる。

  • 解決策:
    Ansibleの varsgroup_vars で変数を定義し、タスクに渡す。

「OSの設定に頼らず、Ansible側で環境を定義する」 のが自動化の原則です。


↑ 目次に戻る


7. まとめ:環境を支配するための「設計の原則」

Ansibleで「コマンドが見つからない」「環境変数が反映されない」時の調査手順です。


【環境 失敗の調査手順】

1. 「絶対パス」で実行して動くか確認する
→ 動くなら、原因はほぼ確実に PATH の欠落(実行コンテキストの差)である。

2. Ansibleの env 出力を確認する
→ 手動時と何が違うのか、どの変数が足りないのかを特定する。

3. 設定ファイルに頼らない
.bashrc が読まれることを期待せず、Ansibleの environment オプションで環境を注入する。


設計の原則

自動化において
「OS側の設定ファイル(.bashrc等)に環境を隠し持たせない」 こと。

必要な環境(PATH、変数)はすべてAnsible側から明示的に与える。

これが「どこでも動く」タスクを作る最短ルートです。


環境問題は
入り口の違いを把握しておけば、大抵の原因は特定できます


↑ 目次に戻る


8. 次回予告

これで「中身(第4回)」と「場所(第5回)」の制御ができるようになりました。

しかし、コマンドを実行した「後」にも罠があります。

shell: grep "error" /var/log/app.log
when: ...

「ログに error は無いはずなのに、なぜか Ansible が失敗(赤色)判定になる」
「Shell側では成功したつもりなのに、Ansibleがそれを汲み取ってくれない」

原因は、ShellがOSに返す
「終わりの合図」
の解釈差にあります。


次回:【Shell編】第6回:なぜ条件分岐が失敗するのか

exit code(終了ステータス)と、Ansibleの when 判定がどう連動しているのか。
その判定ロジックの裏側を解説します。


↑ 目次に戻る


📑 連載の移動
前の記事:【Shell編】第4回 | 次の記事:【Shell編】第6回


📑 【Shell編】全体のまとめはこちら
Ansibleが理解できない理由はLinuxにあった【Shell編】まとめ


🗺️ 初めての方・シリーズの全体像を知りたい方はこちら

本記事は、OSの仕組みからAnsible設計までを繋ぐ連載シリーズの一部です。
「どこから読み始めればいいか」あるいは、「OS/Shell/Ansible編の関係性」 について把握されたい場合は、以下の統合ガイドで整理しています。

Ansibleが理解できない理由はLinuxにあった|統合ガイド


9. 連載一覧:Ansibleが理解できない理由はLinuxにあった【Shell編】

回数とタイトル 内容(概要)
【Shell編】第0回:なぜShellを理解しないとAnsibleは使えないのか AnsibleはShellを通してコマンドを実行している。Ansible → SSH → Shell → Linux の構造を理解し、なぜShell理解が必須なのかを整理する。
【Shell編】第1回:なぜAnsibleで出力が取得できないのか Ansibleでregisterが空になる・エラーが見えない原因はstdout / stderrの違いにある。Shellの出力構造を理解することで原因を特定できる。
【Shell編】第2回:なぜ結果が消えるのか Ansibleで実行結果が見えなくなる原因はパイプ・リダイレクトによる出力先の変化にある。どこに出力が流れたのかを追うことで原因を特定できる。
【Shell編】第3回:なぜgrepで見つからないのか Ansibleでgrepがヒットしない原因は検索対象ではなく入力(stdin)の問題にある。Shellの入力(ストリーム)構造を理解することで原因を特定できる。
【Shell編】第4回:なぜ正規表現で壊れるのか Ansibleで検索や置換が壊れる原因は正規表現の評価ルールにある。文字列ではなくルールとして解釈される仕組みを理解し、リテラルの境界を学ぶ。
【Shell編】第5回:なぜ環境が違うのか 手動では動くのにAnsibleで失敗する原因は実行環境(PATH・環境変数)の差分にある。Shellの実行コンテキストの違いを理解し、環境を制御する。
【Shell編】第6回:なぜ条件分岐が失敗するのか Ansibleのwhen条件が意図通りに動かない原因はexit codeにある。Shellの終了ステータスの判定ロジックを理解することで、正しく条件を組める。
【Shell編】第7回:なぜループがうまく動かないのか Ansibleで繰り返し処理が期待通り動かない原因はShellのループと入力・サブシェルの干渉にある。データの扱い方を理解し、ループを安定させる。
【Shell編】第8回:なぜ途中で処理が止まるのか Ansible実行中に意図せず処理が止まる原因はShellのエラーハンドリング(set -e 等)にある。エラー伝播の仕組みを理解し、停止条件を制御する。
【Shell編】第9回:なぜ変数が意図通りに展開されないのか Ansibleで変数が空になる・壊れる原因はShellのクォートと展開順序にある。値の保護と展開のルールを理解し、安定したコマンドを記述する。
【Shell編】第10回:なぜ値が分割されてしまうのか スペースや改行で意図せず値が壊れる原因はShellの単語分割(word splitting)にある。IFSなどの内部処理の本質を理解し、データの整合性を守る。
【Shell編】第11回:なぜAnsibleの挙動が読めるようになるのか これまでの知識を統合し、AnsibleのエラーをShellの実行プロセスから逆算して分解できるようになる。実務で使える“読み方”を完成させる。

↑ 目次に戻る


0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?