Git を利用した開発環境・テスト環境・本番環境の構成

Gitクラウドテストエンジニア品質保証QA

Git を利用した開発環境・テスト環境・本番環境の構成について解説いたします。

Git とは本来ソースコードなどのバージョン管理を目的として作られたシステムですが、その仕組みを利用することで環境の複製が容易に実現できるため、テスト環境や本番環境も Git で管理しておくと修正プログラムの適用等に大変便利です。

Git リポジトリ構成の例

図では開発環境・テスト環境・本番環境がそれぞれ Git で管理されています。
中央リポジトリが実際にソースコードのバージョン管理をしている箇所で、リポジトリと呼ばれるアクセス起点がネットワーク上に公開されています。
その他の環境は公開されたリポジトリにアクセスして最新のソースプログラムをすばやく自身の環境に取り込むことができます。

Git には フック【hooks】 という仕組みがあり、Git に対するアクションをトリガーとしてなんらかのスクリプト処理を行うことができます。
例えば中央リポジトリに修正コードをpushしたタイミングでテスト環境にもその修正コードを自動で反映させるということもできます。
このような仕組みを利用することにより、テスト環境や本番環境を常に安全に、そして最新の状態に保つことが可能となります。

参考: Git のフックを利用したデプロイの方法

今日では、図でいうところのテスト環境をステージング環境【Staging】、本番環境をプロダクション環境【Production】と呼ぶことが一般的になってきています。
ステージング環境については厳密な定義は存在しませんが、通常プロダクション環境へ適用して良いかどうかの最終確認の場という位置づけになるかと思います。


リポジトリの2つの分類
リポジトリには、リモートリポジトリローカルリポジトリという分類があります。

リモートリポジトリ
リモートリポジトリはネットワーク上で公開され、複数の作業者から共有されます。

ローカルリポジトリ
ローカルリポジトリはリモートリポジトリから環境を復元(クローン)したもので、リモートリポジトリで管理されているファイル群の取得やファイルの編集履歴情報を追跡することができます。
他者からは見えません。

また、ノンベアリポジトリベアリポジトリという分類も存在します。

ノンべアリポジトリ
Git で管理されている実際のファイル群が存在する作業フォルダ(ワーキングディレクトリ)のあるリポジトリ。

べアリポジトリ
ワーキングディレクトリのないリポジトリ。
管理されているファイルの履歴情報のみが存在します。


中央リポジトリ
remote, bare
実際のバージョン管理を担っているリポジトリです。
複数の作業者から共有されるリモートリポジトリであり、Git の管轄外から直接ファイルを編集されることを避けるようワーキングディレクトリの存在しないベアリポジトリを使用します。
開発環境からはpullおよびpushが行われ、ステージング環境やプロダクション環境からはpullが行われます。

中央リポジトリは自前のサーバ上に構築することもできますが、特にこだわりがなければ GitHub などのクラウドサービスを利用しても良いでしょう。
みなさんおなじみの GitHub では 2020年4月に他者に公開されないプライベートリポジトリの利用が無償になりました!

参考: GitHub
参考: GitLab
参考: GitBucket

中央リポジトリはワーキングディレクトリもなく非常にコンパクトなので、ステージング環境やプロダクション環境内に置くような物理サーバ構成が一般的かと思います。

Git リポジトリのサーバ構成の例

まずは Git をインストールします。

>yum -y install git # CentOS
>apt-get install git # Ubuntuなど

remote.gitという名前でリモートリポジトリを作成します。

>cd /path/to
>git init --bare --shared remote.git
Initialized empty shared Git repository in /path/to/remote.git/

リポジトリを SSH 接続で参照させたい場合は、中央リポジトリサーバに SSHD を設定する必要があります
参考: SSHD の設定

開発環境
local, non-bare
まずは中央リポジトリをgit cloneコマンドで複製します。
中央リポジトリにはまだ何もないので、warning が出ていますね。

>cd /path/to
>git clone /path/to/remote.git # 自サーバ内に中央リポジトリがある場合
>git clone https://github.com/sendgrid/sendgrid-php.git # Web上に公開されているリポジトリの場合
Cloning into 'remote'...
warning: You appear to have cloned an empty repository.

中央リポジトリが別サーバに存在する場合、リポジトリが見えていないと以下のようなエラーが出力されます。

Cloning into 'remote'...
fatal: '/path/to/remote.git' does not appear to be a git repository
fatal: Could not read from remote repository.

このような状況が発生した場合は、中央リポジトリをドキュメントルートに置いて Web 上に公開するか、SSH 接続にてリポジトリを見つけます。
セキュリティの観点から、リポジトリは SSH 接続がお勧めです。

# 中央リポジトリを複製する
>git clone https://myserver.com/remote.git # Web上に公開されているリポジトリ
>git clone ssh://ec2-user@myserver.com:/path/to/remote.git # SSH接続(myserver.comにec2-userでSSH接続)
>git clone ssh://ec2-user@12.34.56.78:/path/to/remote.git # SSH接続(IP指定)

SSH 接続に公開鍵が必要な場合、以下のようなエラーが出力されます。

Cloning into 'remote'...
ec2-user@myserver.com: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
fatal: Could not read from remote repository.

このような場合には、以下のように-cオプションにてcore.sshCommandを指定するか、SSH 接続のコンフィグファイルにあらかじめエイリアスを設定しておきます。

# 中央リポジトリを複製する
>git -c core.sshCommand="ssh -i ./keys/pubkey.pem" clone ec2-user@myserver.com:/path/to/remote.git
Cloning into 'remote'...
warning: You appear to have cloned an empty repository.
# エイリアスを指定
>vim /home/ec2-user/.ssh/config # CentOS ユーザec2-userの場合
>vim c:\Users\{ユーザ名}\.ssh\config # Windows

Host rep
  Hostname myserver.com
  User ec2-user
  IdentityFile /path/to/keys/pubkey.pem

>git clone rep:/path/to/remote.git
Cloning into 'remote'...
warning: You appear to have cloned an empty repository.

remoteというディレクトリが作成され、その中にリポジトリの複製ができました。
git remoteコマンドで確認します。

>cd /path/to/remote
>git remote -v
origin  ec2-user@myserver.com:/path/to/remote.git (fetch)
origin  ec2-user@myserver.com:/path/to/remote.git (push)

コミット前にユーザー名と Email アドレスを設定しておきましょう。
全ての Git のコミットにこの情報が付与されます。

# ユーザー名とEmailアドレスを設定する
>git config --local user.name "John Doe"
>git config --local user.email johndoe@example.com

ちなみに以下のエラーが出た場合は、configファイルのアクセス権を変えることで解決します。

Bad owner or permissions on /home/ec2-user/.ssh/config
fatal: The remote end hung up unexpectedly

>chmod 600 /home/ec2-user/.ssh/config

リポジトリの複製が完了したら、次は管理するファイルをコミットしましょう。
git addコマンドでインデックスに追加し、git commitコマンドでコミットします。

>cd /path/to/remote
>cp /src/index.html . # index.htmlをコミットします
>git add .
>git commit -m "First Commit"
[master (root-commit) 8d19ac7] First Commit
 1 file changed, 11 insertions(+)
 create mode 100644 index.html

>git status
On branch master
Your branch is based on 'origin/master', but the upstream is gone.
  (use "git branch --unset-upstream" to fixup)

nothing to commit, working tree clean

これでローカルリポジトリのmasterブランチにindex.htmlがコミットされました。
次に中央リポジトリにコミット内容をpushします。

>git push origin master
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Delta compression using up to 3 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 314 bytes | 314.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To myserver.com:/path/to/remote.git
 * [new branch]      master -> master

下記のエラーが発生した場合は、中央リポジトリの存在するディレクトリ配下にアクセス権限がない状態ですので、アクセス権限を付与します。

error: remote unpack failed: unable to create temporary object directory

これで中央リポジトリのmasterブランチにソースファイルがpushされました。
git statusgit logなどのコマンドで確認します。

>git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean

>git log
commit bb58af04e8501a2e71962478a217d51d19f16d0c (HEAD -> master, origin/master)
Author: John Doe <John@myserver.com>
Date:   Wed Feb 3 11:53:53 2021 +0900
    First Commit

中央リポジトリの方もpushが反映されているか確認してみます。

>git log
commit bb58af04e8501a2e71962478a217d51d19f16d0c (HEAD -> master)
Author: John Doe <John@myserver.com>
Date:   Wed Feb 3 11:53:53 2021 +0900
    First Commit



ステージング環境、本番環境
local, non-bare
開発環境と同じく、まずは中央リポジトリをgit cloneコマンドで複製します。

>git clone ec2-user@myserver.com:/path/to/remote.git
Cloning into 'remote'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (3/3), done.

remoteというディレクトリが作成され、その中にリポジトリの複製ができました。
先ほどpushしたindex.htmlも存在します。

>cd remote
>ls
index.html

各種コマンドで確認します。

>git remote -v
origin  ec2-user@myserver.com:/path/to/remote.git (fetch)
origin  ec2-user@myserver.com:/path/to/remote.git (push)

>git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean

>git log
commit bb58af04e8501a2e71962478a217d51d19f16d0c (HEAD -> master, origin/master, origin/HEAD)
Author: John Doe <John@myserver.com>
Date:   Wed Feb 3 11:53:53 2021 +0900
    First Commit

開発環境から中央リポジトリへソースファイルの修正が行われた際、ステージング環境や本番環境にその修正を反映します。
通常、これらはフックを利用して自動的に行われます。
一般的にステージング環境はdevelopブランチ、本番環境はmasterブランチへのpushを反映します。

>git pull origin develop # develoopブランチへのpushをステージング環境へ反映
>git pull origin master # masterブランチへのpushを本番環境へ反映


参考: Git ワークフロー(ブランチモデル)とその手順
参考: Git コンフリクトの解消
参考: Git のフックを利用したデプロイの方法
参考: git push を Chatwork や Slack へ通知する方法

コメント