miauのブログ

はてなダイアリー「miauの避難所」をはてなブログに移行しました。 https://zenn.dev/miau に移行しようと考え中

本番サーバにチェックアウトしちゃダメですか?

この記事。まず訳がちょっと違うかな?という箇所があるのでそこを補っておくと。

しかしコードが実動サーバに乗る段階ではそれはローカルな作業用コピーではなく、エキスポートされた完成品だから、この問題が起こる。

こう訳されてる箇所があるけど、

When code is rolled to a live server from a repository, it is supposed to be done as an export rather than as a local working copy, and hence this problem.

実働サーバにコードを載せる場合は、ローカルな作業用コピーとして取得するのではなくエクスポートするべきだ。(だが今回はローカルな作業用コピーを本番に置いているので)問題になっている。

みたいな意味合いじゃないかなーと。(書いてて自信なくなってきた・・・。)

で、「svn export は違うだろ」と思ったので、とりあえず思うところを書いてみます。適宜ツッコミお願いします。


運用上良いと思う順に書いてみます。

案1: 本番環境をワーキングコピーにする

本番環境からリポジトリに直接アクセスして、svn checkout する運用です。もちろん .svn は Apache 側の設定でアクセス不可にしておきます。

こうすることの利点はいろいろあるんですが・・・。

  • 運用負荷が低い
    • svn update だけで更新できる
    • svn:executables を指定していれば、チェックアウト時に実行権限が付加されるので chmod する必要もない
  • 無駄が少ない
    • 必要なファイルだけ更新される
  • 削除ファイルを適切に管理できる
    • 最新モジュールを取得して上書きする運用では、いちいち削除する必要がある

といったところです。

インフラ周りの事情で別のソリューションを導入しているケースも多いでしょうけど、通常構成では svn update での運用がベストだと思いますよ。

この運用を行う場合の注意点

svn checkout した際に衝突が発生すると、元のファイルがマージされたものに置き換わってしまいます。もし衝突の可能性がある(=本番サーバ上で更新しているファイルがある)場合は、あらかじめ

svn merge --dry-run -r BASE:HEAD .

とやって、衝突が発生しないことを確認してから svn update すれば、いくらか安心です。(シビアな環境では HEAD じゃなくてリビジョン固定にしたほうがいいですが。)

より確実に更新するためには、本番リリース用のブランチを作っておいて、衝突が発生しない形にしたほうがいいかもしれません。

案2: Trac で差分モジュールを取得してアップロードする

ということで、本番サーバ上で svn を使うのがベストだとは思うんですが、これが難しい環境というのもあるでしょう。本番環境からリポジトリにアクセスできなかったり、.svn ファイルがあると困る環境だったり。その場合は svn export するよりもまず、Trac 等の利用を考えたほうがいいと思います。

具体的には以下のような運用になります。

  1. Trac でリリース用のチケットを切っておく
  2. Subversion でリリース用のタグを切る
    • タグは必須ではないですが、作っておいたほうが diff する際にリビジョン指定が要らないので楽です。
    • たとえばこんな感じです。
      • 2009-09-17 リリースぶん: /tags/20090917(前回リリースしたもの)
      • 2009-09-25 リリースぶん: /tags/20090925(今回リリースしたいもの)
  3. 上記のチケットに diff のリンクを貼る
    • TracWiki 記法なら「diff:tags/20090917//tags/20090925」
    • URL でいうと「http://(Tracのパス)/changeset?new_path=tags/20090925&old_path=tags/20090917」みたいな
  4. 上記の diff ページの最下部「Zip アーカイブ」をクリック
    • この .zip には、変更されたファイルだけが含まれています
    • tags の位置を変えている場合は、trac.ini の downloadable_paths を適切に編集しておきましょう
  5. リリース
    • .zip をサーバにアップロードして解凍するなり、解凍してアップロードするなり
  6. チケットをクローズ

本番機へのリリースがそれほど頻繁でない環境に限られるかもしれませんが、この運用でうまくいっていたような気がします。

案1 と違って

等は必要になるのでお気をつけください。

また、この方法では「本番上で設定ファイルを書き換えておく」といった運用は行えません。

案3: svn export

全ファイルを取得する必要があるので、大規模サイトではやりたくないですが・・・全ファイルクリーンな状態で欲しい場合もあると思いますので、その場合は svn export でもいいと思います。

svn update で .svn を除外指定してアップロード、みたいなことをやってもいいと思いますけど。ケースバイケースでしょうね。

まとめ

今回の問題はあくまでも「本番に .svn が置かれる運用だったのに、.svn が除外指定されていなかったこと」なので、「svn update じゃなくて svn export しろ」という意見はちょっと乱暴すぎる気がする。セキュリティ屋さんはたまに運用効率とか無視したアドバイスとかしちゃうけど、これを元に変な運用ルールとかできちゃうと迷惑なのでやめてほしいなー。

ついでに

細かい疑問とか補足とか。

ドットファイルのアクセス制限

Most web servers are configured by default to disallow access to directories that begin with a period (the traditional prefix for a hidden file or folder in UNIX)

Webサーバのデフォルトの構成では、名前がドットで始まるディレクトリ(UNIXでは伝統的に隠れファイルや隠れディレクトリ)をアクセス不可にすることが多い。

とあるけど、XAMPP デフォルトの httpd.conf だと

<FilesMatch "^\.ht">
    Order allow,deny
    Deny from all
</FilesMatch>

となっていて、ドットファイルすべてを弾く形にはなってないんですけど。XAMPP だからですかね?

DirectoryIndex?

〔*訳注: まあ、‘ディレクトリリスティングを返さない’という構成にするのがふつうでしょう。〕

とあるけど、DirectoryIndex の指定とドットファイルを拒否する設定は別じゃないかなと。

(追記)
ma さんのコメントにあるように、DirectoryIndex じゃなくて Options -Indexes のほうですね。失礼しました。

Subversion 以外では・・・

分散リポジトリであれば本番機からリポジトリに直接アクセスできない場合も、うまく運用できたりします。mercurial での運用でよければ、以下の本に環境に応じたさまざまな使い方が載っています。

入門Mercurial Linux/Windows対応

入門Mercurial Linux/Windows対応

仕事で mercurial 使ったことがないので、本当にうまくいくのかはわからないのですが・・・とりあえずオススメです。

(2012-04-10 追記)use-commit-times=true について

ブコメで

seiunsky svn, 運用, development
自宅ではsvn updateですw/安全面(コンフリクトで死ぬ)を考えるとステージングで svn update→ 本番に rsync とかですかねぇ。あと、svn update するならサーバ側はuse-commit-times=true しといた方が良いですよね 2010/02/11

と書かれてたんですが、当時 use-commit-times=true することの重要性をわかってなかったんですよね(好みの問題だと思ってた・・・)。改めて、このあたりの解説にリンクしておきます。

~/.subversion/config か /etc/subversion/config で設定する感じと。