😎

クラウドに頼らないIaC入門〜Vagrant + Linux VMで作る自分だけの実験場〜

2025/03/15に公開

1. はじめに

本記事をご覧頂き、ありがとうございます。
クラウド環境を構築するためのガイドとなるべく、作成しました。
筆者はGCPの使用経験がありますが、まずは特定のクラウド環境に依存しない形で構築をすすめます。
今回はVagrantとゲストOSをUbuntuで構築します。

最初に、Vagrantは、開発環境の自動化ツール で、仮想マシン(VM)の作成・管理を簡単にできる特徴があります。

特に、以下の点でメリットがあります:
環境構築が一瞬Vagrantfile を1つ用意すれば、環境を統一できる
クラウド環境のローカル版が作れる → Terraformと組み合わせると強力
簡単にコピー&共有できる → チーム開発や副業のテスト環境に最適

今回はVagrantを使ってコマンドラインでCI/CDパイプラインを構築するまでを行います。
テストに使う言語はpythonで、簡単なコードを記述します。

Infrastructure as Code:IaCっと聞くとなんとなく難しいイメージがあるかもしれません。
ですが、要素を分解していくと意外と単純です。
楽しんでいきましょう!


2. 対象読者

クラウド環境でよく使われているCI/CDパイプラインですが、

  • 初めて触る
  • 聞いたことはある
  • 図解付きで解説してほしい
    このような方を対象とします。

想定作業時間は2~3時間程度です。
正直、中上級者にとっては冗長に思うかもしれません。
環境構築からやっていくので、一緒に手を動かしなら楽しみましょう!


3. Vagrant の基本的な仕組み

Vagrantは、VirtualBox や KVM, Hyper-V などの仮想化ソフトを管理するラッパー のようなもの。
コマンドを実行するだけで、仮想マシンの作成・削除・変更が可能です。

  1. Vagrantfile に環境の定義を記述
    ※自動的に生成されますが、後ほど設定を追加します。
  2. vagrant up で仮想マシンを起動
  3. vagrant ssh でログイン
  4. vagrant destroy で削除可能

4. Vagrant の導入(Ubuntu 20.04 の仮想マシンを作る)

1.** Vagrant のインストール**

Mac/Linux(Homebrew または apt)

brew install vagrant

または:

sudo apt update && sudo apt install -y vagrant

Windows(Chocolatey)

choco install vagrant

コマンドラインでもインストールできそうですが、僕は以下の公式サイトからダウンロードしました。
https://www.vagrantup.com/


[公式サイト]
Vagrant


Community→Downroadをクリックすると、以下のページが出てくるので、
Vagrant-download


OSはWindowsを使っているので、Windows版のi686を選びました。
Windows版


ダウンロードしたインストーラをクリックするとインストールが開始します。
Vagrant-install


利用規約にチェックしてインストール開始
利用規約にチェックしてインストール開始


しばらく待ちます。
vaigrant-install中


5分ぐらいで完了しました。
vaigrant-install完了


2. ** 仮想マシンを作成**

  1. Vagrantfile を作成
mkdir vagrant-test
cd vagrant-test

power-shell

vagrant init ubuntu/focal64

screen-shot

これで Vagrantfile という設定ファイルが作成される。

  1. 仮想マシンを起動
vagrant up

色々とログが出力されていますが、
仮想OS起動!

VirtualBox側でもVMが起動していることが分かります。
virtualbox

VirtualBox や Hyper-V で Ubuntu の仮想マシンが起動できた。

  1. 仮想マシンにログイン
vagrant ssh

ちゃんと接続できましたね!
vagrant ssh

SSHで仮想マシンに接続できた。


4. Vagrant の利点

機能 説明
環境を簡単に再現 Vagrantfile を共有すれば、全員が同じ環境を再現可能
仮想マシンのスナップショット管理 vagrant snapshot save で状態を保存し、restore で戻せる
ネットワーク設定が柔軟 config.vm.network でポートフォワーディングやIP指定が可能
クラウド環境のテスト AWS/GCPのローカル版を作れる
Dockerとの連携 vagrant up でDockerコンテナを含めた仮想環境を立ち上げ可能

5. Vagrant を CI/CD・クラウド学習に活用する

Vagrantを使うと クラウドを使わずにローカルでAWS/GCPのような環境をエミュレート できます。

例えば:

1. Terraform + Vagrant

vagrant up  # Ubuntu環境を作成
terraform apply  # Terraformで仮想マシンのプロビジョニング

メリット: AWS/GCPにデプロイする前にローカルでテスト可能

2. CI/CD(Jenkins)+ Vagrant

vagrant up
vagrant ssh -c "sudo apt install -y jenkins"

メリット: ローカルでクラウドを使わずにCI/CDを実験できる


続いてpythonで簡単なプログラムを作って、CI/CDパイプラインを構築していきます。

6. Python アプリケーションの作成と VM への展開

1. まずはローカルで Python アプリケーションを作成

まず、ホスト PC 上で簡単な Python アプリケーションを作成します。

# vagrant-test ディレクトリ内に app ディレクトリを作成
mkdir app
cd app

bash

VSCodeを立ち上げます。

bash

app.py
# Hello World アプリケーションを作成
def hello():
    return "Hello, World!"

if __name__ == "__main__":
    print(hello())

簡単な例ですが、動作確認しておきましょう。
vscode

テストもしておきます。pytestをインストールしましょう。

pip install pytest
test_app.py
# シンプルなテストを作成
import unittest
from app import hello

class TestHello(unittest.TestCase):
    def test_hello(self):
        self.assertEqual(hello(), "Hello, World!")

if __name__ == "__main__":
    unittest.main()

テストも通過しましたね。
pytest

# requirements.txt を作成
pytest==8.3.5

2. Vagrantfile を編集して共有フォルダを設定

Vagrantfile を編集して、作成したアプリケーションが VM 上で利用できるように設定します。
筆者の場合は
user/vagrant-test/Vagrantfile にファイルがあります。
共有フォルダでプロビジョニングのための設定を加えます。

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/focal64"
  
  # ポート転送設定(必要に応じて)
  config.vm.network "forwarded_port", guest: 5000, host: 5000
  
  # 共有フォルダ設定
  config.vm.synced_folder "./app", "/home/vagrant/app"
  
  # Python と必要なツールをインストールするプロビジョニング
  config.vm.provision "shell", inline: <<-SHELL
    apt-get update
    apt-get install -y python3 python3-pip python3-venv git
    # 仮想環境のセットアップ
    cd /home/vagrant/app
    python3 -m venv venv
    . venv/bin/activate
    pip install -r requirements.txt
  SHELL
end

vscode

プロビジョニングとは

プロビジョニングとは

Vagrantにおけるプロビジョニングとは、仮想マシンが起動した後に自動的に実行される環境構築の処理です。今回の記事では、config.vm.provision "shell", inline: <<-SHELL ... SHELL の部分がこれにあたります。

プロビジョニングの利点は、手動での環境構築作業を自動化できる点です。JavaやPython、Jenkinsなどのインストール、設定ファイルの作成、権限の調整など、通常なら手作業で行う操作をスクリプト化することで、再現性の高い環境を簡単に構築できます。

これにより、「特定の人しか構築できない環境」ではなく、「誰でも同じ手順で作れる環境」が実現します。開発チームでの環境統一や、新メンバーのオンボーディング時間短縮にも大きく貢献するため、Infrastructure as Codeの重要な要素の一つと言えるでしょう。

3. VM の再起動とプロビジョニングの実行

変更した Vagrantfile を適用します。

# vagrant-test ディレクトリに戻る
cd ..
# VM を再起動してプロビジョニングを実行
vagrant reload --provision

結構時間がかかります。
bash


bash

4. VM 上でアプリケーションを実行

vagrant ssh
cd ~/app
ls

vm login

python3 app.py  # "Hello, World!" と表示されるはず
pytest test_app.py  # テストが通るはず
exit

動作に問題はなさそうですね。
run and test

VM上でpythonが実行できた。

7. CI/CD パイプラインの構築(Git編)

1. Git リポジトリの初期化(option)

✅今回は簡略化のために下記のパイプライン構築の時点ではgitの設定は外しています。
しかし、本来であればgitでコード管理する場合が多いため、必要な人はセットアップしておいてください。
不要な方はスキップできます。

cd app
git init
.gitignore
__pycache__/
*.py[cod]
*$py.class
venv/
.pytest_cache/
pytest-cache-files-9ruznpyk/

vscode

git add .
git commit -m "Initial commit with Hello World app"

power-shell

2. GitLab CI 設定ファイルの作成

.gitlab-ci.yml
stages:
  - test
  - deploy

test:
  stage: test
  image: python:3.9
  script:
    - pip install -r requirements.txt
    - pytest test_app.py
  only:
    - main

deploy:
  stage: deploy
  image: python:3.9
  script:
    - echo "Deploying application..."
    - mkdir -p ~/.ssh
    - echo "\$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - ssh-keyscan -H \$DEPLOY_SERVER_IP >> ~/.ssh/known_hosts
    - scp -r app.py requirements.txt \$DEPLOY_USER@\$DEPLOY_SERVER_IP:/home/\$DEPLOY_USER/app/
    - ssh \$DEPLOY_USER@\$DEPLOY_SERVER_IP "cd /home/\$DEPLOY_USER/app && python3 -m venv venv && . venv/bin/activate && pip install -r requirements.txt && python app.py"
  only:
    - main
git add .gitlab-ci.yml
git commit -m "Add GitLab CI configuration"

vscode

8. CI/CD パイプラインの構築(Jenkins編)

1. VM 上に簡易 CI/CD 環境を構築 (Jenkins を使用)

Vagrantfile を更新してJenkinsをインストールします。

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/focal64"
  
  # ポート転送設定
  config.vm.network "forwarded_port", guest: 5000, host: 5000
  config.vm.network "forwarded_port", guest: 8080, host: 8080  # Jenkins用
  
  # 共有フォルダ設定
  config.vm.synced_folder "./app", "/home/vagrant/app"
  
  # Python と必要なツールをインストールするプロビジョニング
  config.vm.provision "shell", inline: <<-SHELL
    apt-get update
    apt-get install -y python3 python3-pip python3-venv git
    # Jenkins のインストール
    apt-get install -y openjdk-11-jdk
    wget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | apt-key add -
    sh -c 'echo deb https://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'
    apt-get update
    apt-get install -y jenkins
    systemctl start jenkins
    systemctl enable jenkins
    # 初期パスワードを表示
    echo "Jenkins initial admin password:"
    cat /var/lib/jenkins/secrets/initialAdminPassword
    # Python 環境のセットアップ
    cd /home/vagrant/app
    python3 -m venv venv
    . venv/bin/activate
    pip install -r requirements.txt
  SHELL
end

vscode

2. Vagrantfileを更新して適用

#appにいる場合は
cd ..
vagrant reload --provision

ちゃんと完了しましたね。
bash

3. Jenkins の設定

  1. ブラウザで http://localhost:8080 にアクセス
# 既存のリポジトリ設定を削除
sudo rm /etc/apt/sources.list.d/jenkins.list
sudo rm /usr/share/keyrings/jenkins-keyring.gpg 2>/dev/null || true

# 新しい方法でキーを追加
curl -fsSL https://pkg.jenkins.io/debian/jenkins.io-2023.key | sudo tee /usr/share/keyrings/jenkins.io.key > /dev/null
echo "deb [signed-by=/usr/share/keyrings/jenkins.io.key] https://pkg.jenkins.io/debian-stable binary/" | sudo tee /etc/apt/sources.list.d/jenkins.list > /dev/null

# パッケージリストを更新
sudo apt update

# Jenkinsをインストール
sudo apt install -y jenkins

うまくいったと思ったらJenkisがこけています。
logs

vagrant sshでVMに繋がった状態なので、ログを見てみます。
期待するJavaのバージョンと違ったみたいですね。

~
~
#中略
Mar 15 01:35:37 ubuntu-focal jenkins[7364]: Running with Java 11 from /usr/lib/jvm/java-11-openjdk-amd64, which is older than the minimum required version (Java 17).
Mar 15 01:35:37 ubuntu-focal jenkins[7364]: Supported Java versions are: [17, 21]

Javaを入れなおしてみます。

# Java 17をインストール
sudo apt update
sudo apt install -y openjdk-17-jdk

# Jenkinsが使用するJavaバージョンを設定
sudo update-alternatives --set java /usr/lib/jvm/java-17-openjdk-amd64/bin/java

# Jenkinsを再起動
sudo systemctl restart jenkins

今度はちゃんとlocalhost:8000でアクセス出来ていますね!
Jnekins起動!
3. 表示されたJenkinsの初期パスワードを入力(VM内の /var/lib/jenkins/secrets/initialAdminPassword にあります)

Jnekinsにログインする

sudo cat /var/lib/jenkins/secrets/initialAdminPassword

4. 推奨プラグインをインストール

jenkins-plugin


しばらく待ちます。
jenkins-plugin2

5. 管理者アカウントを作成

※プラグインインストールが終わったら勝手に遷移していました。

jenkins-admin

6. Jenkinsインスタンスを作成します。

jenkins-instance生成

jenkins-ready

これでJenkinsが使えるようになりました

7. 新しいパイプラインジョブを作成

  • 「新規ジョブ作成」→「パイプライン」を選択

jenkins-pipeline


jenkins-pipeline

  • 以下のようなパイプラインスクリプトを設定:
pipeline {
    agent any
    
    stages {
        stage('Setup') {
            steps {
                sh 'cp -r /home/vagrant/app/* .'
            }
        }
        stage('Install') {
            steps {
                sh 'python3 -m venv venv || true'
                sh '. venv/bin/activate && pip install -r requirements.txt'
            }
        }
        stage('Test') {
            steps {
                sh '. venv/bin/activate && pytest test_app.py'
            }
        }
        stage('Deploy') {
            steps {
                sh 'mkdir -p /home/vagrant/deploy'
                sh 'cp app.py requirements.txt /home/vagrant/deploy/'
                sh 'cd /home/vagrant/deploy && python3 -m venv venv || true'
                sh 'cd /home/vagrant/deploy && . venv/bin/activate && pip install -r requirements.txt'
                sh 'cd /home/vagrant/deploy && . venv/bin/activate && python app.py'
            }
        }
    }
}
Jenkins-pipelineの構造

Jenkins-pipelineの構造は意外とシンプルです。
stage('Setup'), stage('Install') のようにstageというsteps {}にまとめたコマンドをさらにまとめて、sategeに分割して実行します。
dockerfileでcpで依存関係をコピーしたり、pip installするのに似ていますね。

Configure→パイプラインをクリックして、上記のコードを貼り付け、Saveを押します。
jenkins-pipeline
パイプラインの作成が完了しました。
jenkins-pipeline

ビルド実行をクリックしてしばらく待ちます。
ビルド実行

失敗してしまいましたね。
ビルド失敗!

ビルドに失敗したので、実行に必要なJavaインストール、各権限を付与->パイプラインをビルドします。

  1. 権限の問題

    # Jenkinsユーザーに必要なディレクトリへの権限を付与
    sudo chown -R jenkins:jenkins /home/vagrant/app
    sudo mkdir -p /home/vagrant/deploy
    sudo chown -R jenkins:jenkins /home/vagrant/deploy
    
  2. Pythonやpipの問題

    # JenkinsユーザーがPythonとpipを使えるようにする
    sudo -u jenkins python3 --version
    sudo -u jenkins pip3 --version
    

    これらの設定が完了したら、Jenkinsパイプラインを再度実行してみてください。

また、app.pyやtest_app.pyなどのファイルが確実に存在することも確認しておくと良いでしょう:

ls -la /home/vagrant/app

ビルド成功!

9. 最終的なVagrantfile

今回実施した内容を反映したvagrantfileを載せておきます。

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/focal64"
  
  # ポート転送設定
  config.vm.network "forwarded_port", guest: 5000, host: 5000  # Pythonアプリ用
  config.vm.network "forwarded_port", guest: 8080, host: 8080  # Jenkins用
  
  # 共有フォルダ設定
  config.vm.synced_folder "./app", "/home/vagrant/app"
  
  # プロビジョニングスクリプト
  config.vm.provision "shell", inline: <<-SHELL
    # システムの更新
    apt-get update
    apt-get upgrade -y
    
    # 必要なパッケージをインストール
    apt-get install -y git curl wget

    # Python環境のセットアップ
    apt-get install -y python3 python3-pip python3-venv
    
    # Java 17のインストール
    apt-get install -y software-properties-common
    add-apt-repository -y ppa:openjdk-r/ppa
    apt-get update
    apt-get install -y openjdk-17-jdk
    update-alternatives --set java /usr/lib/jvm/java-17-openjdk-amd64/bin/java
    
    # Jenkinsのインストール
    curl -fsSL https://pkg.jenkins.io/debian/jenkins.io-2023.key | tee /usr/share/keyrings/jenkins.io.key > /dev/null
    echo "deb [signed-by=/usr/share/keyrings/jenkins.io.key] https://pkg.jenkins.io/debian-stable binary/" | tee /etc/apt/sources.list.d/jenkins.list > /dev/null
    apt-get update
    apt-get install -y jenkins
    systemctl start jenkins
    systemctl enable jenkins
    
    # Pythonアプリの初期セットアップ
    mkdir -p /home/vagrant/app
    cd /home/vagrant/app
    
    # アプリケーションフォルダが空の場合、サンプルアプリを作成
    if [ ! -f app.py ]; then
      echo 'def hello():
    return "Hello, World!"

if __name__ == "__main__":
    print(hello())' > app.py
      
      echo 'import unittest
from app import hello

class TestHello(unittest.TestCase):
    def test_hello(self):
        self.assertEqual(hello(), "Hello, World!")

if __name__ == "__main__":
    unittest.main()' > test_app.py
      
      echo 'pytest==7.4.0' > requirements.txt
    fi
    
    # Python仮想環境のセットアップ
    python3 -m venv venv || true
    . venv/bin/activate
    pip install -r requirements.txt
    
    # デプロイ用ディレクトリの作成
    mkdir -p /home/vagrant/deploy
    
    # Jenkins用の権限設定
    chown -R jenkins:jenkins /home/vagrant/app
    chown -R jenkins:jenkins /home/vagrant/deploy
    
    # Jenkins内でpythonコマンドを実行できるようにするための設定
    usermod -a -G vagrant jenkins
    chmod 755 /home/vagrant
    
    # Jenkinsユーザーが一時ディレクトリを作成できるようにする
    mkdir -p /var/lib/jenkins/workspace
    chown -R jenkins:jenkins /var/lib/jenkins/workspace
    
    # Jenkins初期パスワードを表示
    echo "Jenkins initial admin password:"
    cat /var/lib/jenkins/secrets/initialAdminPassword
  SHELL
end

これで、ローカル PC で Python アプリを作成し、Vagrant で仮想環境を構築し、その中で CI/CD パイプラインを構築するところまでの流れが完成します。

このフローのポイント:

  1. アプリケーションとテストコードはホストマシンで作成
  2. 共有フォルダを通じて VM に同期
  3. VM 上で Jenkins を使って CI/CD を実行
  4. すべてがオフラインで完結するため、外部サービスに依存せず実験可能

これを「自分だけの実験場」として活用することで、クラウドと同様の CI/CD の概念を学べます。また、この基盤をベースに、次のステップでよりリッチなアプリケーションや複雑な環境へと発展させることができます。

10. さいごに

Jenkinsのパイプラインは、確かに見た目は複雑に見えますが、本質的には「実行したい一連のコマンドをステージごとに整理して順番に実行する」だけのものです。

簡単に言うと:

  1. ステージ(stage): 「Checkout」「Build」「Test」「Deploy」など、論理的な作業単位
  2. ステップ(steps): 各ステージ内で実行する具体的なコマンド(主にシェルコマンド)

例えば、手動でやるなら:

# チェックアウト
git clone リポジトリURL

# インストール
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

# テスト
pytest test_app.py

# デプロイ
mkdir -p deploy
cp app.py requirements.txt deploy/
cd deploy
python app.py

これをJenkinsパイプラインで表現すると、単にこれらのコマンドを整理して記述しているだけです。CI/CDツールの多くは、このような単純な考え方をベースにしています。

11. まとめ

本記事では、クラウドに頼らずにVagrantとJenkinsを使って独自の実験環境を構築する方法を紹介しました。この「自分だけの実験場」の強みは、
 ✅コストがかからない
 ✅ネットワーク環境に依存しない
 ✅何度でも失敗と再構築を繰り返せる
などの点にあります。

CI/CDパイプラインの本質は「一連のコマンドをステージごとに整理して順番に実行する」というシンプルな考え方です。この基本を理解すれば、GitHub ActionsやGitLab CIなど他のツールにも応用できます。

今回構築した環境は入門レベルですが、さらにコンテナ化、Kubernetes、複雑なアプリケーションへと発展させることも可能です。まずは小さく始めて、徐々に複雑な環境へと挑戦していくことで、クラウドネイティブな技術スタックを効率よく学べるでしょう。

またこのような記事が読みたい方は、
✓評価
✓保存
✓フォロー
をよろしくお願いします!

皆様のコメント💬が励みになります。
何か聞きたいこと/ツッコミ、なんでもOKです。

また、Xでも技術の話をつぶやいているので、フォローよろしくお願いします。
https://x.com/kazuma_Eduscope

それはまた、次回の記事でお会いできるのを楽しみにしております。
ではまた!!

Discussion