株式会社クイックのWebサービス開発blog

HAPPYなエンジニア&デザイナーのブログです

CSEのサイト内検索結果がGoogle検索と大幅に違う場合は、検索エンジンを作り直すと良いらしい

yumeです。今回は勢いに任せて書きます。

GoogleCSE(Custom Search Engine)を利用してサイト内検索を実装したものの、
いつまで経っても検索結果がダメダメでした。

かれこれ3週間以上悩んでいたのですが、
結果、新規の検索エンジンを作り直したらうまくいきました。それだけの話。

経緯

既存サイトの新規ディレクトリ配下に、新しいコンテンツを作成

看護roo!というサイト(www.kango-roo.com)の新コーナーとして、/ki/配下に記事ページを100件超追加しました。
数日後、ちゃんとクロールされたことが確認できました。

f:id:aimstogeek:20170929154253p:plain

この後、/ki/専用のサイト内検索フォーム設置を予定しており、
めでたくインデックス登録されたことだし、GoogleのCustom Search Engineを利用して実装することに。

CSEで既存の検索エンジンにラベルを追加

このサイトでは、すでに全コーナーのサイト内検索を実装済
自然に、「既存の検索エンジンを使って、ラベルだけ新規作成しよう」となりました。

既存の検索エンジンに、www.kango-roo.com/ki/ のラベルを作成。

おかしい!!!!!検索結果が1件しかない!!!

「site:www.kango-roo.com/ki/ 看護師」でGoogle検索したときには100件超ヒットしたのに、
CSEのコンソールで「看護師」と検索しても1件しかでない!!!!!!!

迷走

  • sitemap.xmlを急遽作ってアップしたり
  • SearchConsoleから上限数までインデックス登録リクエストしたり
  • 意味もなく2週間待ってみたり

    途方に暮れていたその時、このページにたどり着きました。
    much less results returned by CSE than Google search with "site" restriction - Google プロダクト フォーラム
    https://productforums.google.com/forum/#!topic/customsearch/Ek-feIf-TLQ/discussion

    え?new Google Accountをcreateするって?

    とりあえずアカウントは変えずに検索エンジンを変えた

    細かいところはよくわかりませんが、そういう風に考えてみるのかーと思って、
    同じアカウントで新規に検索エンジンを作成。

    /ki/専用の検索エンジンを作りました。

    うまくいった。一体なんだったんだ。。。
    f:id:aimstogeek:20170929155831p:plain

    他のラベルでは問題なく絞り込みできるので、
    ラベルの設定が悪い、などではなさそうでした。

    まとめ

  • CSEの検索結果がGoogle検索と全然違うよってことがある
  • ラベルで正しく設定していても意図したとおりにならないことがある
  • アカウントとか検索エンジンを新しく作ってみれば解決することもある


    おまけ

    というわけで、看護師のフリー素材コーナーをオープンしました!
    www.kango-roo.com

エンジニアの本音が出てる名言集

エンジニアチームにはインフラを専任とするT親方と呼ばれるエンジニアがいます。
T親方はエンジニアの手本となるような言動が多く、よく名言を残すんですが社内に留めておくのはもったいないのでインターネットで公開したいと思い立ちました。

 

デスクは汚いですが、ちゃんと配置は把握している派です。
matsBです。(๑•̀ㅂ•́)و✧

 

T親方の名言集

PRD環境やDEV環境をどうするかの議論の中での一言。


Dev環境って実態はインフラ的にはDev環境じゃあないですよね、

往々にして

 インフラを携わってたら分かる、あるあるネタの一つ。

短い文章の中から、実体とそれに伴う諦めが滲む、いい言葉です。

 

 

deployジョブのログを見て、一部自動テストが失敗してるのにデプロイ結果が「Finished: SUCCESS」になってるのを見て一言。

うける

 とにかく破壊力がすごい。

作った人を責めるわけでもなく、問題提起をするわけでもない。

けど言われた方はすぐにでも修正したくなるような、いい言葉です。

※このあと、ちゃんと対応してくれました。

 

 

運が悪いと言えるほどレアなバグを踏んでサービス落ちたけど、レアバグなのは過去の負債が原因だったときの一言。

建て増しでシステムが複雑になると表出する現象も複雑になるということですね
(そうやって出来上がったものを影響ないように簡素化するのは難しい。。

全体を見れてないと出せない重い言葉ですね。

負債に対する感情が、驚き→意欲→怒り→諦め→無感情→悟り。と一周半ぐらいして初めて出てくるような、いい言葉です。

 

 

資料化されてない仕様(↑のレアバグの要因)を見つけた時の一言。

未知の既知のバグ

バグがあることは知ってる。資料化されてないのも知ってる。

1年以上携わってるのにまだ知らない仕様を見た時に言える、いい言葉です。

 

 

資料を渡して気になる点を見つけた時の一言。

データが離れてるのが気になりますね。。

気になるだけですぐ忘れるんですが f:id:aimstogeek:20170929190154g:plain

 本質的な事以外は興味がない親方。

指摘はするが解決はしないスタイルをマイルドに表現した、いい言葉です。

 

 

 たまたま見つけた、誰も知らない設定を見つけた時の一連。 

2月9日 11:58
Header set Pragma: "no-cache" env=nocache
こんなのも入ってますね、心の片隅に留めておきましょう。。(忘れる

 

4月14日 18:21

。。忘れてた(宣言通り

 自分で言って自分で忘れる。それを見越した発言。

忘れたことは宣言通りなので、誰もT親方を責めることは出来ない、いい言葉です。

 

 

自分の知らないファイヤーウォールの設定を見た時の一連。

T親方:サイトのdeploy job作るときにサーバにSSH通るようにファイヤーウォール弄りました?

matsB:確かイジったはずです!それもT親方にお願いしてSSH通るようにしてもらった記憶が・・・笑

T親方:忘れていい記憶に振り分けたのかなー f:id:aimstogeek:20170929192122g:plain

 振り分けられてしまったのなら、仕方ない。

自分自身の作業を忘れて他責にしそうになった時に使える、いい言葉です。

 

 

 

T親方の名言の一部を書いてみましたが、いかがでしょうか!

心にグッとくる言葉から、同じような境遇や状況になった時に使える言葉が、あったのではないでしょうか。

是非、T親方の名言を使ってみてください。

【AWS CloudFront + S3】Origin Access Identity を利用した S3 のアクセス制限

こんにちは。クイックSREチームのみっちーです。

前回は、CloudFront+WAFを利用して、開発環境等のIP制限を実装する方法をご紹介しました。
引き続き今日は、S3へのアクセスを「特定のIPアドレス」または「CloudFrontからのみ」許可する設定をご紹介します。

CloudFront+S3のセットで利用する際は、
CloudFrontからのみ、S3へアクセス可能とする場合が多いのではないでしょうか。
ただその場合だと、同一名称でファイルを上げ直した時に、キャッシュが残って困る事があるかと思います。
(この点については、query stringを付けた運用をしているのであれば気にならないと思いますが・・・)

そんなときは、今回ご紹介する方法を試してみて下さい。
S3へ直接アクセスが可能になるため、毎度キャッシュを消さなくても良いことが運用上のポイントです。

なお、今日ご紹介する方法は単独でもいいですし、前回の内容と組み合わせて使うことも可能です。
それではさっそく設定方法を見ていきましょ~ ✧(・ㅂ・)و

前提

  • CloudFront + S3 の構成。

  • 開発者は、S3、CloudFrontの両方へ直接アクセス可能にしたい。

  • ユーザは、CloudFront経由でしか画像にアクセスできないようにしたい。

  • アクセス制限の対象となるCloundFrontとS3は、それぞれ事前に作成済みである。

  • 運用イメージは以下の通り。

    f:id:aimstogeek:20170925190949j:plain

手順概要

必要な手順は大まかに以下の2つです。

1. [AWS CloudFront] Origin Access Identity の設定

2. [AWS S3] IPアドレスベースのbucket policyを追加

手順詳細

1. [AWS CloudFront] Origin Access Identity の設定

AWSコンソールにログインし、「Services」->「CloudFront」をクリックします。

次に、アクセス制限をかけたいS3とセットになっているCloudFront Distributionを選択して、Origins の「Edit」をクリックします。 f:id:aimstogeek:20170926174037j:plain


Origin Settings

AWS CloudFrontからのみアクセスできるように、一意の Access Identity(ID) を追加します。 f:id:aimstogeek:20170926174402j:plain

  • Restrict Bucket Access Yes を選択します。
    ※ ここをYesとすると、これ以降の2項目が表示されるようになります。

  • Origin Access IdentityCreate a New Identity を選択します。
    ※ CloudFrontからのアクセスであることを示す一意のIDです。
    ここでは新規作成していますが、
    他のCloudFront Distributionで作成したIDを使いまわすことも可能です。

  • Grant Read Permissions on BucketYes,Update Bucket Policy を選択します。
    S3 bucket policyに、自動でAccess Identity(ID)を追記してくれます。
    Noを選ぶと、手動追加となり不便です。
    特に理由が無ければYesを選びましょう。


問題なければ、下段のYes Editをクリックして反映させましょう。

なお、設定変更直後はStatusがIn Progressとなり、この間は設定が反映されていません。
しばらく(20~40分程度)して反映完了すると、StatusがDeployedになります。



2. [AWS S3] IPアドレスベースのbucket policyを追加

続いて、S3のbucket policy設定です。

AWSコンソールにログインし、「Services」->「S3」をクリックします。
次に、アクセス制限をかけたいBucketを選択して、
Permissionsの「Bucket Policy」をクリックします。

「CloudFront Origin Access Identity」の bucket policy

この時点で、以下のようにPrincipal: CloudFront Origin Access Identityのpolicyが自動で追加されていると思います。 f:id:aimstogeek:20170928190308j:plain

        {
            "Sid": "2",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <一意のID>"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::test.s3.hoge.com/*"
        },




IPアドレスベースのbucket policy

続いて、特定のIPアドレスからのアクセスを許可するように、ポリシーを追加します。
f:id:aimstogeek:20170928185212j:plain

{
            "Sid": "Allow-from-specific-IP-only",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3::test.s3.hoge.com/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "<許可するIPアドレス/サブネットマスク>"
                    ]
                }
            }
        }

問題なければ、Saveしましょう。設定は即時反映されます。

以上で設定は完了です。
これで、「特定のIPアドレス」または「CloudFrontからのみ」アクセスが許可される形となります。


いかがでしたか。
ちなみに、S3 bucket policyに「CloudFrontのIP & 特定IP」を記載する方法でもアクセス制限の実現は可能です。
ただしこの場合、CloudFrontのIPが動的に変わるため、適当なタイミングでIPリストの更新をする必要があり、少々不便です。

今回ご紹介した方法では、
EffectがAllowどうしのポリシーを複数束ねることで、or条件として使うことができる特性を利用し、IPリストの手動更新を不要としています。
S3 bucket policyは考え方に少々クセがあって、慣れるまでは難しいかなと個人的には感じています。

ということで次回はS3のbucket policy(評価順序等)について書いてみたいと思います。
興味を持って頂けたらぜひまた読んでみて下さい!

それでは~ (・о・) /

この記事のトップへ戻る

【AWS CloudFront】 WAF を利用したアクセス制限を実装する

こんにちは。クイックSREチームのみっちーです。

今日は、弊社で設定しているCloudFrontのIP制限方法をご紹介したいと思います。
開発環境等で「ユーザには見せたくないけど、関係者だけは見れるようにしたい!」と言った話にも、AWS WAFを使えば簡単に対応できます。
お困りの方はぜひ試してみて下さい!

それではさっそく行ってみましょ~ ✧(・ㅂ・)و

前提

  • CloudFrontに対して、IPアドレスによるアクセス制限を行いたい。

  • アクセス制限の対象となるCloudFrontは、事前に作成済みである。

手順概要

必要な手順は大まかに以下の2つです。

  1. [AWS WAF] ACLの作成

  2. [AWS CloudFront] 作成したACLのattach

手順詳細

1. [AWS WAF] ACLの作成

AWSコンソールにログインし、
「Services」->「WAF & Shield」をクリックします。

続いて、AWS WAF」->「Configure web ACLの順に選択して、WAFの設定画面に進みましょう。 f:id:aimstogeek:20170919192659j:plain


Step 1:Name web ACL

ここでは、ACLの名称を定義します。細かい設定はこの後で順番にやっていきます。

f:id:aimstogeek:20170919192710j:plain

  • Web ACL name: 任意のACL名を入力します。
    ※ ここでは、test-ACLとしています。

  • Region「Global(CloudFront)」を選択します。
    ※ ここを間違えると、CloudFrontにattachできなくなります。注意です。

上記以外は特に気にしなくてOKです。次へ進みましょう!


Step 2:Create conditions

続いて、IPaddressのlist設定を行います。
ここで作成したlistを元に、Whitelistにするか、Blacklistにするかを決めていきます。
※ 今回はWhitelistです。

IP match conditions「Create conditions」をクリックします。 f:id:aimstogeek:20170919192805j:plain


すると以下の画面が出てくるので、それぞれ設定を行いましょう。 f:id:aimstogeek:20170919192815j:plain

  • Name: 任意のlist名を入力します。
    ※ ここでは、allow-ip-addressとしています。

  • Address許可したい「IPアドレス」または「範囲」を記載し、「Add IP address or range」をクリックします。
    ※ 記載できるサブネットマスクの範囲は、/8, /16, /24 または、/32 です。
    ※ ここでは、111.123.123.1/32 を設定しています。

  • Filters in IP match conditionに、追加したIPアドレスが表示されていることを確認します。

問題なければ、次へ進みましょう。


Step 3:Create rules

先程作成したIPaddressのlistを元に、Filtering Rules(Whitelistにするか、Blacklistにするか)を決めていきます
※ 今回はWhitelistとして設定します。

まずはCreate ruleをクリックして、「Filtering Rules」を作成します。 f:id:aimstogeek:20170920111415j:plain


f:id:aimstogeek:20170920111651j:plain

  • Name: 任意のFiltering Rules名を入力します。
    ※ ここでは、test-ruleとしています。

  • Add conditions「does」、「originate from an IP address」の順に選択し、
    先程作成したlistの「allow-ip-address」を対象に選択します。


    つぎに、作成したFiltering Rulesを適用する条件を指定します。 f:id:aimstogeek:20170920111107j:plain

  • Add rules to a web ACLRulesで、
    先程作成したFiltering Rules「test-rule」を選択します。

  • Action「Allow」を選択します。
    ※ Filtering Rules(test-rule)にマッチングした場合にどうするか、を定義します。

  • Default action「Block all requests…」を選択します。
    ※ Filtering Rules(test-rule)にマッチングしなかった時にどうするか、を定義します。


終わったらReview and createを押して、最終確認です。
確認して問題なければ作成しましょう。
次はいよいよCloudFrontにACLの設定をattachします!


2. 作成したWAFのACLを、CloudFrontにattachします。

AWSコンソールにログインし、「Services」->「CloudFront」をクリックします。

次に、アクセス制限をかけたいCloudFront Distributionを選択して、
General の「Edit」をクリックします。 f:id:aimstogeek:20170920131255j:plain


Distribution Settings

AWS WAF Web ACLで、先程作成したACL(test-ACL)を選択します。
問題なければ、下段のYes Editをクリックして反映させましょう。

なお、設定変更直後はStatusがIn Progressとなり、この間は設定が反映されていません。
しばらく(20~40分程度)して反映完了すると、StatusがDeployedになります。

アクセス確認

反映完了後(StatusがDeployedになる)、適当なファイルにアクセスしてみましょう。
Whitelistに記載の無いIPアドレスからのアクセスであれば、
下図のようにErrorとなるはずです。

f:id:aimstogeek:20170920131904j:plain




以上で設定は完了です。

いかがでしたか。AWS WAFを使えば、CloundFrontにも簡単に制限が掛けられますね。
不慮の事故を防ぐという意味でも、念のために設定しておいて損は無いのかなと思っています。

第二回社内LT大会を開催

もうすでに夏バテの始まっているsatopiiです。

今月上旬、社内エンジニア陣で集まって第二回社内LT大会を開催しました。

f:id:aimstogeek:20170714203728j:plain

LTとはライトニングトークの略で、持ち時間5分で行うプレゼンテーションのことです。

まだ第二回目ということで最大10分と緩めのルールで実施しました。

写真はありませんが、LT大会の様子を紹介いたします!

第一回については昨年クリスマス前に実施し、そのまま年末年始休暇に突入してレポートするのを忘れました。ご了承ください。

テーマ

第一回に続いて、今回もテーマ設定はなし。
各々が、今伝えたいことをプレゼンしました。

ルール

  • 16:00-18:00開催 (登壇者:9名)
  • 一人持ち時間:最大10分
  • 発表後に全員で投票

投票

一人一票制としました。

  • おもしろい!と感じたLT発表者へ投票
  • 発表者も投票権あり

  • 最優秀賞
  • マネージャー賞

発表内容

  • 3年目の失敗
  • おじさん病と対策
  • フロントエンドの言葉たち
  • 豪華プロジェクトをステイサムで乗り切る
  • ゲームをつくってみた
  • 置かれた環境を10倍楽しむ方法〜Mランドに学ぶ〜
  • Power of Dark Side 〜5分で分かるネットの闇(入門編)〜
  • 給料の仕組み
  • いろんなMVPを勝手に決めてみた

タイトルだけでも魅力的ですね。

テーマを設けていなくても、Web系ネタが4本集まってしまうところは、さすがエンジニアの集団といったところでしょうか。 その他は、ビジネス系ネタ4本、私の内容のないネタ1本と、ほど良いバランスでした。

※各スライドの詳細については、各発表者が記事を書く可能性がありますのでお楽しみに(*´ڡ`●)

投票結果

最優秀賞

最優秀賞を獲得したのは「Power of Dark Side 〜5分で分かるネットの闇(入門編)〜」を発表した、てるさんでした!
ネットの海は広く深い……改めて認識させられる内容でした。

マネージャー賞

マネージャー賞は「置かれた環境を10倍楽しむ方法〜Mランドに学ぶ〜」を発表した、ゆめちゃんが受賞!
学生時代の経験を語ってくれたのですが、『自分が置かれた環境に受け身になってはいけない』というメッセージが心に染みるプレゼンでした。

振り返り

  • 準備も解散もスムーズ!
    • 第二回目ということもあり、会場セッティングや後片付けはみんな協力的でサクッと完了。
  • リアルタイムコーディング系はトラブルの可能性あり。
    • 今回リアルタイムコーディングに挑戦した二人は、開発環境や事前に作っておいたものが動作しないなどのトラブルに見舞われ、10分を超えてしまう結果に…。
      • リアルタイムコーディングする場合は、事前に会社のマシンで動作するか確認が必要ですね!
  • 意外と5分で終わる人がいない
    • 最大10分というルールだったので、言いたいことを伝えきるプレゼンが多めでした。
      • 次回以降は、最大10分というルールの中でも『5分ぴったり賞』があっても面白いかもしれません。
  • 新卒が研修で参加できなかった
    • 次回のLT大会開催時期には研修が終わっていますし、新卒の皆さんの参加に期待!!

タイムオーバーで「おじさん病と対策」の対策編が聞けなかったので、対策編がこのブログで展開されることに期待しています。

登壇した皆さん、お疲れ様でした( ˘ω˘)

Baculaデータを別サーバに退避してリストア【運用手順編その2】

【構築手順編その1】【構築手順編その2】【運用手順編】 と連続して書きましたが、そのほかにもやってる事を書きたいと思います。
【運用手順編】にまとめて書こうとしたのですが、長くなってしまったので分けました。


マフラーを外すタイミングが分かりません。
matsBです。(๑•̀ㅂ•́)و✧


なんならヒートテックも、どのタイミングから着なくていいのか分かりません。

Baculaを使ってると、DR(Disaster Recovery)どうしようとか、Directorが壊れたらどうしようとか、Catalogが消えたらどうしようとか、Volumeデータ消えたらどうしようとかとかとか・・・・思ったりしたことはありませんか?
後で説明しますが、BaculaはVolumeデータさえあればどこでもリストアできます。Catalog無くても大丈夫です。
その使い方&設定等の説明を含めて、簡単なDR的な事をBaculaでやってみたので紹介します。

前提

サーバ情報

役割 ホスト名 IPアドレス
Director quick-dir 10.0.0.1
Client quick-fd 10.0.0.2
Client(DR用) quick-dr 10.0.0.3
Storage quick-sd 10.0.0.10

Baculaデータを別サーバに退避してリストア

Baculaを使って簡単なDR(Disaster Recovery)的な意味で、他の拠点や他のサーバに一部データを退避させたいなーって方用の説明です。

前提

【事実】
・ホスト名はquick-dr
・quick-drにはMySQLが入ってる
【願望】
・2週間だけ別サーバに退避させたい
・DBのCatalogは最新が望ましい
・いつでも別サーバに移行出来るようにしたい

bacula-dir のインストール

【構築手順編その1】でやってるので説明は省きますが、とりあえずquick-dirと同じようなものにしていきます。

[root@quick-dr ~]# yum install -y bacula-client bacula-common bacula-console bacula-console-bat bacula-debuginfo bacula-devel bacula-director bacula-docs bacula-libs bacula-libs-sql bacula-traymonitor
[root@quick-dr ~]# /bin/sh /usr/libexec/bacula/create_mysql_database -u root -p
[root@quick-dr ~]# /bin/sh /usr/libexec/bacula/make_mysql_tables -u root -p
[root@quick-dr ~]# egrep "^db_password=" /usr/libexec/bacula/grant_mysql_privileges
db_password=bacula_quick
[root@quick-dir ~]# /bin/sh /usr/libexec/bacula/grant_mysql_privileges -u root -p

bacula-dir のconfigをコピーとVolumeデータのコピー

って言っても、やりたい事を箇条書きしただけです。

[root@quick-dr ~]# cat /var/spool/bacula/config-rsync.sh
#!/bin/bash

# Directorのconfigを全てコピー
rsync -avz --delete -e ssh root@10.0.0.1:/etc/bacula/ /etc/bacula/
# Storage Daemonのconfigをコピー
rsync -avz --delete -e ssh root@10.0.0.10:/etc/bacula/bacula-sd.conf /etc/bacula/
# Storage Daemonの設定のIPアドレスを置換
sed -i -e 's/10.0.0.10/127.0.0.1/g'  /etc/bacula/bacula-dir.conf
# スケジュールを消す
sed -i -e 's/  Run /#  Run /g'  /etc/bacula/bacula-dir.conf
# File Daemonを自分のホスト名に置換
sed -i -e 's/quick-dir/quick-dr/g'  /etc/bacula/bacula-fd.conf

Catalogとデータが無いので何も出来ませんが、まぁこれで一応動くようにはなってるはずです。 そして、欲しいデータを雑にコピーしてきます。

・quick-fdのバックアップファイル
[root@quick-dr ~]# rsync -avz -e ssh root@10.0.0.10:/data/bacula-backup/quick-fd-* /data/bacula-backup/
・Catalogの最新バックアップファイル
[root@quick-dr ~]# rsync -avz -e ssh root@10.0.0.10:/data/bacula-backup/localhost-FullVol-2017-04-13_1150 /data/bacula-backup/

Catalogのデータについては、基本的に最新のバックアップファイルだけで大丈夫です。

Catalogのリストア

Catalogに何も無い状態なので、Volumeデータだけ持ってきてもリストアが出来ない事はないのですが・・・このあと説明しますが面倒です。
Catalogのリストアはmysqldumpしか方法が無いとか思われがちですが、Baculaにはbextractとblsというコマンドがあって、組み合わせて使えばリストアが出来るようになっています。

[root@quick-dr ~]# cat /var/spool/bacula/catalog_restore.sh
#!/bin/bash

BaseDir=/var/spool/bacula

#過去分をリストアしたい場合はここで日付を指定
#FileNameDate=`date --date '7 days ago' +%Y-%m-%d`
FileNameDate=`date +%Y-%m-%d`

#Catalogのファイル名を取得
CatalogFileName=`ls /data/bacula-backup/localhost-FullVol-${FileNameDate}_* | awk -F"/" '{print $4}'`

#Bootstrapファイルを作成
touch ${BaseDir}/restore-bacula-catalog.bsr

#Bootstrap内に必要情報を記述
echo Volume=${CatalogFileName} > ${BaseDir}/restore-bacula-catalog.bsr
bls -j -V ${CatalogFileName} /data/bacula-backup | sed -n 3p | awk '{print $4"\n"$5}' | sed -e "s/SessId/VolSessionId/g" | sed -e "s/SessTime/VolSessionTime/g" >> ${BaseDir}/restore-bacula-catalog.bsr

#BaculaのCatalogを直接リストア
bextract -b ${BaseDir}/restore-bacula-catalog.bsr -V /data/bacula-backup/${CatalogFileName} /data/bacula-backup /data/catalog

#リストアしたファイルをMySQLに突っ込む
mysql -u bacula -pbacula_quick bacula  < /data/catalog/var/spool/bacula/bacula.sql

#不要ファイルを削除
rm -rf /data/catalog/* ${BaseDir}/restore-bacula-catalog.bsr

#configのIPアドレスの書き換え
sed -i -e 's/10.0.0.10/127.0.0.1/g'  /etc/bacula/bacula-dir.conf

#bacula 関連を再起動
/etc/init.d/bacula-sd restart
/etc/init.d/bacula-dir restart

blsでバックアップされた時の情報を抽出して、Bootstrap内に必要情報(Volume/VolSessionId/VolSessionTime)を入れて、bextractでリストアしてます。
これはCatalogに限らず、bextractとblsを使えばVolumeデータだけでリストアが出来ます。
なので最悪Directorが入ったサーバが壊れて使えなくなっても復旧は可能なので、VolumeデータとConfigだけ退避させておけば心強いです。

必要期間分のVolumeデータのコピー

まぁこの辺は取りたいVolumeデータを書いてるだけなので、大したことは書いてないですが晒します。

[root@shoukai-dr ~]# cat /var/spool/bacula/data-rsync.sh
#! /bin/bash -x

TODAY=`date +%Y-%m-%d`
ONEWEEKAGO=`date --date '7 days ago' +%Y-%m-%d`
TWOWEEKAGO=`date --date '14 days ago' +%Y-%m-%d`
DAYOFWEEK=`date -d $TODAY '+%w'`

rsync -avz -e ssh root@10.0.0.10:/data/bacula-backup/localhost-FullVol-${TODAY}_* /data/bacula-backup/ && rm -f /data/bacula-backup/localhost-FullVol-${ONEWEEKAGO}_*

    if [ ${DAYOFWEEK} -eq 0 ] ; then      # if文で判定に使用している値'0'は日曜日を指す。
        echo 'today is Sunday.'
        rsync -avz -e ssh root@10.0.0.10:/data/bacula-backup/quick-fd-FullVol-${TODAY}_* /data/bacula-backup/ && rm -f /data/bacula-backup/scat-FullVol-${TWOWEEKAGO}_*
        else
        echo 'today is not Sunday.'
        rsync -avz -e ssh root@10.0.0.10:/data/bacula-backup/quick-fd-DifferentialVol-${TODAY}_* /data/bacula-backup/ && rm -f /data/bacula-backup/scat-DifferentialVol-${ONEWEEKAGO}_*
    fi

exit 0

rsync && rm -f」と直列にしてるのはrsync出来なかった時(quick-sdが死んでる時)にquick-drのデータを消してくなかったからです。
って言うのも、東京に災害があってquick-sdが死んだ2週間後に「事業を再開させましょう!」→「保存期間2週間で、データありません!」じゃ話にならないですよね。
もっとマシな書き方あると思うんですが、面倒になっただけでした。笑

bacula-dirにquick-drのクライアントの設定configを作成

必要なスクリプトは揃ったので、これをBaculaで自動化させます。

[root@quick-dir ~]# cat /etc/bacula/client/00_quick-dr.conf
############################
# Job Information
############################
Job {
  Name = "quick-dr-job"
  Client = quick-dr
  JobDefs = "DefaultJob"
  FileSet= "quick-dr File Set"
  Schedule = "WeeklyCycleAfterBackup"
  Full Backup Pool = etc-Pool
  Client Run Before Job = "/var/spool/bacula/config-rsync.sh"
  Client Run Before Job = "/var/spool/bacula/data-rsync.sh"
  Client Run After Job = "/var/spool/bacula/catalog_restore.sh"
  Priority = 13
}

############################
# FileSet
############################
FileSet {
  Name = "quick-dr File Set"
}

############################
# bacula-fd Information
############################
Client {
  Name = quick-dr
  Address = 10.0.0.3
  FDPort = 9102
  Catalog = MyCatalog
  Password = "fd-password"
  File Retention = 1 days
  Job Retention = 1 days
  AutoPrune = yes
}

全てのJobが完全に終わった後じゃないと意味が無いので、JobのPriorityを13にして一番最後にJobが走るようにしています。
00_quick-sd.confと一緒で何もバックアップされず、空のVolumeだけが作成されます。

上記ファイルを外部ファイルとして読み込む

[root@quick-dir ~]# grep "00_quick-dr.conf" /etc/bacula/bacula-dir.conf
@/etc/bacula/client/00_quick-dr.conf
[root@quick-dir ~]# /etc/init.d/bacula-dir restart
Stopping bacula-dir:                                        [  OK  ]
Starting bacula-dir:                                        [  OK  ]

これで設定が完了です。
Directorのステータスを見るとこんな感じの順序でjobが走ってくれます。

*status Director
bacula-dir Version: 7.4.4 (20 September 2016) x86_64-redhat-linux-gnu redhat
Daemon started 06-Apr-17 19:04, conf reloaded 06-Apr-2017 19:04:40
 Jobs: run=78, running=0 mode=0
 Heap: heap=385,024 smbytes=543,712 max_bytes=628,117 bufs=976 max_bufs=1,243

Scheduled Jobs:
Level          Type     Pri  Scheduled          Job Name           Volume
===================================================================================
Differential   Backup    10  13-Apr-17 02:05    quick-fd-job       *unknown*
Full           Backup    11  13-Apr-17 02:10    quick-sd-job       *unknown*
Full           Backup    12  13-Apr-17 02:10    BackupCatalog      *unknown*
Full           Backup    13  13-Apr-17 02:10    quick-dr-job       *unknown*
====

MySQLのReplication使えよーとかDRDBでいいじゃん!とかあると思いますが、quick-drはBaculaの検証にも使ってたりしていて、MySQLに書込みしたいのでこんな形になりました。


ってまぁ、クイックではこんな感じでBaculaを運用しています。 無理矢理使ってる感はありますが、、、Baculaに集約させとけばとりあえずは迷わないですし、後々別の方法を取るにしろスケールするにしろ見れば分かる状態にしています。

即実践できるBaculaの設定例【運用手順編】

前々回の【構築手順編その1】、前回の【構築手順編その2】 では構築部分を紹介しました。
今回は【運用手順編】として、どうBaculaを運用しているかを設定例やスクリプトを書きたいと思います。
ここおかしいよー!とかあれば、コソッと教えてもらえたらありがたいです!

ラーメンのスープが髭に付くことが最近の悩み。
matsBです。(๑•̀ㅂ•́)و✧


髭は伸ばしてる訳ではなく、単に伸びてるだけです。

運用部分は会社や規模によって大きく変わるので、一概にこれが正しいとは言えないんですがクイックではこうやってるよーって事を書いていきます。
逆に、「うちではこう運用してるよー」ってのがあれば、コメントに書いても直接連絡して頂いても嬉しいです!

前提 (前の記事からのおさらい)

前提環境

MySQLをインストール済。
iptables等のFirewallは一旦無視してます。

サーバ情報

役割 ホスト名 IPアドレス
Director quick-dir 10.0.0.1
Client quick-fd 10.0.0.2
Client(DR用) quick-dr 10.0.0.3
Storage quick-sd 10.0.0.10

bat(BaculaのGUIツール)

慣れてくると基本的にはコマンド(CUI)の方が圧倒的に早いんですが、慣れるまではGUIの方が分かりやすいです。
普段使ってるパソコンがWindowsであれば、Xming等を入れてdisplayをforwardできるようにしておいて、SSHクライアントもX11をforward出来るようにしておいて下さい。

動作環境の準備

[root@quick-dir ~]# yum install -y xorg-x11-apps
[root@quick-dir ~]# xeyes

とかでX Window Systemを使ってるアプリを起動させてちゃんと表示できれば、基本的にbatが使える環境になってます。
もしサーバ側にX11の準備をしてなくて「Error: Can’t open display:」とかで見れない場合は、

[root@quick-dir ~]# yum groupinstall "X Window System"

とかでインストールしてやれば、不要なものも入ってきますがとりあえずで動かすことは出来ます。

batのインストール

[root@quick-dir ~]# yum install -y bacula-console-bat

batの設定

[root@quick-dir ~]# cat /etc/bacula/bat.conf
Director {
  Name = quick-dir
  DIRport = 9101
  address = localhost
  Password = "dir-password"
}

Directorのサーバに入れたくなければ、自分のテスト環境等にbatとX Window Systemを入れて

address = localhost
 ↓
address = 10.0.0.1

って感じにIPアドレスをDirectorのサーバにすれば大丈夫です。

自動で古いVolume(Purged)のDELETEとファイル削除

【構築手順編】で書いた設定例だとVolumeはリサイクルされず、保存期間が過ぎたVolumeはPurgedになります。
これはデフォルトだと、「どのクライアント」の「どのレベルのバックアップ」で「何が最新なのか」が全然分からなかったので、Label Formatを全部ユニークでパッと見で全部分かるようにしたかったからです。

Label Format = "${Client}-${Level}Vol-${Year}-${Month:p/2/0/r}-${Day:p/2/0/r}_${JobId}"
quick-fd-DifferentialVol-2017-04-08_1130ってVolume名になります。

ユニークにしてるので、リサイクルさせると訳わからん状態になるからリサイクルさせてません。
ただ、bacula的にはPurgedになるだけでCatalogから削除もされないしVolumeの実体ファイルもそのまま残るので、いつかbacula-sdの容量が100%になって破綻してしまいます。
そこで、一日一回キレイに削除する作業が必要になりますが、手動はしんどいのでBaculaで自動化させます。

前提

【事実】
・quick-dirとquick-sdは別サーバ。
・quick-sdにbconsoleを入れていて、向き先はquick-dirになっている。
・bacula-sdの設定でファイルは/data/bacula-backup/に全て置かれている。
【願望】
・この削除作業は全てのバックアップが完了した後に実行したい。

purgedの数をチェック

シンプルに下記のようなシェルで、ステータスがPurgedのVolumeの数を見れます。

[root@quick-sd ~]# cat /var/spool/bacula/check_purged.sh
#!/bin/bash
echo "list volumes" | bconsole | grep "Purged" | awk {'print $4'} | wc -l

purgedの状態のVolumeのファイル削除とDELETE

PurgedをgrepしてVolume名を特定させて、ファイル削除して、BaculaからDELETEさせてます。

[root@quick-sd ~]# cat /var/spool/bacula/purged_delete.sh
#!/bin/bash
for f in `echo "list volume" | bconsole | grep "Purged" |awk -F" " '{print $4}'`; do
  rm -f /data/bacula-backup/$f;
  echo "delete volume=$f yes" | bconsole;
done

BaculaのJobにする

「・この削除作業は全てのバックアップが完了した後に実行したい。」
とあるので、cron等で定期実行してしまうとバックアップ完了時間が前後した時に対応できなくなってしまいます。
なので空のバックアップJobを作成して、シェルだけ動くようにしました。
本当はBaculaに全部やらせなくても解決出来る問題なんですが、せっかくだからBaculaで完結させてみた。って感じです。

bacula-fd(Backup Client)のインストール

[root@quick-sd ~]# yum install -y bacula-client

bacula-fd(Backup Client)の設定は前回説明したので割愛します。

bacula-dirにquick-sdのクライアントの設定configを作成

[root@quick-dir ~]# cat /etc/bacula/client/00_quick-sd.conf
############################
# Job Information
############################
Job {
  Name = "quick-sd-job"
  Client = quick-sd
  JobDefs = "DefaultJob"
  FileSet= "quick-sd File Set"
  Schedule = "WeeklyCycleAfterBackup"
  Full Backup Pool = etc-Pool
  Client Run After Job = "/var/spool/bacula/purged_delete.sh"
  Priority = 11
}

############################
# FileSet
############################
FileSet {
  Name = "quick-sd File Set"
}

############################
# bacula-fd Information
############################
Client {
  Name = quick-sd
  Address = 10.0.0.10
  FDPort = 9102
  Catalog = MyCatalog
  Password = "fd-password"
  File Retention = 1 days
  Job Retention = 1 days
  AutoPrune = yes
}

JobのPriorityを11にすることによって、他のバックアップ(Priority=10)が完了した後に、purged_delete.shが動くことになり「・この削除作業は全てのバックアップが完了した後に実行したい。」を満たす事になります。
FileSetが空なのでファイルは何もバックアップされず、空のVolumeだけが作成されて1日でPurgedになるようにしています。

上記ファイルを外部ファイルとして読み込む

[root@quick-dir ~]# grep "00_quick-sd.conf" /etc/bacula/bacula-dir.conf
@/etc/bacula/client/00_quick-sd.conf
[root@quick-dir ~]# /etc/init.d/bacula-dir restart
Stopping bacula-dir:                                        [  OK  ]
Starting bacula-dir:                                        [  OK  ]

これで全てBaculaが自動で古いVolume(Purged)のDELETEとファイル削除をしてくれるようになりました。

注意点

今回説明した設定だと4週間の保存期間ですが、運用してる途中で「やっぱり2ヶ月」残したいなーと思ってPoolのVolume Retentionを「28 days」から「60 days」に変更したとします。

  Volume Retention = 28 days
    ↓
  Volume Retention = 60 days

この変更して再起動させても新規で作成されたVolumeが60日の保管期間になるだけで、古いVolumeは保存期間が4週間のままです。なので4週間経つとPurgedにされてしまいます。
そんな時は、下記のように変更したいVolumeと何日保存するかを書いて、VolRetentionを一括変更すれば楽な運用ができます。

[root@quick-dir ~]# cat retention.sh
#!/bin/bash

VolumeName=quick-fd-DifferentialVol
RetentionDate=60days

for f in `echo "list volume" | bconsole | grep $VolumeName |awk -F" " '{print $4}'`; do
  echo "update volume=$f VolRetention=$RetentionDate" | bconsole

done

jenkinsでデータのRestore

クイックではjenkinsを使ってますが、jenkinsのプラグインにBaculaは存在してませんでした。
jenkinsでポチッとビルドするだけでDBの復旧とか、DEV環境にデータ復元してすぐ使えるようになったら楽なのになーと思いやってみることにしました。

jenkinsサーバにbconsoleをインストール

[root@jenkins ~]# yum install bacula-console.x86_64
[root@jenkins ~]# cat /etc/bacula/bconsole.conf
Director {
  Name = quick-dir
  DIRport = 9101
  address = 10.0.0.1
  Password = "dir-password"
}

jenkinsのJobの設定

リストア後に何かしらの作業をしたいのですが、bconsoleからリストアするとBacula側からリストアが完了したかどうかを教えてくれません。
なので、「echo “messages”| bconsole」を実行してこっちから聞きに行かないと駄目です。
とりあえず特定のdumpをリストアして、リストア完了を待って、DBに入れるところまでを書きました。

#!/bin/bash

FileDate=`date +%y%m%d`
Termination=`echo "messages" | bconsole | tail | grep Termination | awk -F" " '{print $2$3$4$5}'`
SleepCount=1

echo "messages" | bconsole
echo "restore storage=quick-sd \
      client=quick-fd \
      where=/tmp/bacula-restores \
      restoreclient=jenkins \
      file=/var/spool/bacula/quick-fd_${FileDate}db.dump \
      mark current done yes" \
| bconsole 

while [ "$Termination" != '***RestoreError***' -a "$Termination" != 'RestoreOK' ]; do
  VolumesName=`echo "messages" | bconsole | tail | grep Termination | awk -F" " '{print $2$3$4$5}'`
  sleep 30
  if [ ${SleepCount} -lt 60 ] ; then
    SleepCount=`expr 1 + $SleepCount`
  else
    exit 0
  fi
done

if [ "${Termination}" = "RestoreOK" ] ; then
  mysql -u root -p????? -h quick-fd < /tmp/bacula-restores/var/spool/bacula/quick-fd_${FileDate}db.dump
  rm -rf /tmp/bacula-restores/*
fi

なんか無理矢理感が凄いですが、とりあえずバックアップされたdumpを突っ込むまではいけました。
JobじゃないからClientRunBeforeJobとか使えないですし、RestoreClientRunBeforeJobとか定義出来たらめっちゃ楽なのになー・・・・とか思いましたが、機能追加に期待ですね!

注意点

・リストア実行する前に「echo “messages” | bconsole」をしないと溜まってるmessagesが出てきてしまいます。
・sleepとCountの値は適当です。

その他

Baculaはとにかくマニュアルが充実してて、分からない事をググればすぐに探せるのがいいですね。(英語だけど)
まだまだ認知度もユーザも、ソリューションに比べたら少ないですがBaculaが広まったら情シスの年間予算とか凄い削れるのになーって思ったりしました。
Windowsも使えますし、ファイルサーバとか容量大きなバックアップはBaseJobを使えばその後は時間を掛けずにバックアップが可能になりますし。
まだまだ調べきれてない事も多いですが、今後も色々Baculaを触っていきたいと思います。