Gobble up pudding

プログラミングの記事がメインのブログです。

MENU

GPU付きマシンでUbuntu 18.04.4 LTS Desktop amd64をLive DVDを動かしてデータ消去

f:id:fa11enprince:20200531020724j:plain
例によって備忘録です。これから試すところも書いてあります(特にデータ消去)。
データ消去は結構課題ですね。
Windowsなら結構いいソフトがあるとは思うのですが、
ddコマンドで乱数を書いてデータ消去というのをどんなOSのものであってもやりたいことがあります。
そんなときに使えそうな、DBANは古くからありますが、
そもそもLegacyモードでしか起動しないのと、SSDを認識してくれません。困った。
とはいえ大半のBIOSにデータ消去機能が入っていたリハするのですが…たまにないやつがいる。
さてどうしようとなるわけで、そうだ、Ubuntuをインストールして、shredコマンドで消そうと思いっ立ったのです。 しかしそもそもUbuntuを入れようとするとハマりポイントがいっぱい。

前提条件

この前提条件が違うとうまくいかない可能性があります。特にBIOSとハードウェアが絡んでくるかもしれません。
Ubuntu 18.04.4 LTS Desktop amd64

ソフト バージョン 備考
OS Windows 10 DVD作成+編集用
GPU NVIDIA Geforce RTX 2070 Super
チップセット Z390M-S01

ファイラーを開いてOther Locationsというところを押すとWindowsで使っていたディスクが見えると思います。

ISOをダウンロードします

http://releases.ubuntu.com/18.04.4/
ここからデスクトップ版をダウンロードします

Rufasを使ってUSBに書き込みます

このときDVDでもいいのですが、ハマり回避のためにUSBのほうが良いかと思われます。
というのもGPU付きマシンだとドライバが入ってないという罠があるので、そのまま突き進むとプチ砂嵐になるので、
Windows上からgrubのテキストファイルを書き換える必要が出てきます。

書き込むときも罠があります。 基本Secure BootがONでCSMもON、UEFIモードでやりたいので、このようにします。
何のことかピンとこない場合は、とりあえず普通にWindows 10を使っている場合、こうなってるはずです。

GPT UEFI(CSM無効)の組み合わせでUSBを作成

GPT UEFI(CSM)無効の組み合わせでUSBを作成します。あとは設定をいじらなくてOKです。
こうするとBIOSの設定がCSM: Enable, Boot: UEFI Only, Secure Boot: Enable1 の状態でインストールできる(Secure Boot Disableにしたほうが良いという説もある)。 あえてレガシーでやりたい場合は
MBR BIOSまたはUEFIで書き込んで、
BIOSの設定がCSM: Disable, Boot: Legacy First, Secure Boot: Disableとかでインストールできるはず…だが、検証した時は時間がなくてよくわからず。
まぁ、このニーズはあまりないんでないかな。というかMSIの場合、Windowsを消さないとどうもLegacyに変えられないっぽい。

USBの内容を書換え

2か所書き換えます。実は前者は不要だと思われます。
マウントされているUSBドライブをのぞくと普通にファイルが見えるので次のファイルを開きます。
先頭の行数と-+はないですが、diffっぽい形式で書いてます。
要はquiet splashnomodesetに書き換えます。
isolinux/txt.cfg

 5 - append  file=/cdrom/preseed/ubuntu.seed boot=casper initrd=/casper/initrd quiet splash ---
 5 + append  file=/cdrom/preseed/ubuntu.seed boot=casper initrd=/casper/initrd nomodeset ---

 9 - append  file=/cdrom/preseed/ubuntu.seed boot=casper only-ubiquity initrd=/casper/initrd quiet splash ---
 9 + append  file=/cdrom/preseed/ubuntu.seed boot=casper only-ubiquity initrd=/casper/initrd nomodeset ---

13 - append  boot=casper integrity-check initrd=/casper/initrd quiet splash
13 + append  boot=casper integrity-check initrd=/casper/initrd nomodeset ---

こちらも同じ要領で書き換えます
boot/grub/grub.txt

16 -    linux    /casper/vmlinuz  file=/cdrom/preseed/ubuntu.seed boot=casper quiet splash ---
16 +    linux    /casper/vmlinuz  file=/cdrom/preseed/ubuntu.seed boot=casper nomodeset ---

21 -    linux   /casper/vmlinuz  file=/cdrom/preseed/ubuntu.seed boot=casper only-ubiquity quiet splash---
21 +    linux   /casper/vmlinuz  file=/cdrom/preseed/ubuntu.seed boot=casper only-ubiquity nomodeset ---

26 -    linux   /casper/vmlinuz  file=/cdrom/preseed/ubuntu.seed boot=casper only-ubiquity quiet splash oem-config/enable=true ---
26 +    linux   /casper/vmlinuz  file=/cdrom/preseed/ubuntu.seed boot=casper only-ubiquity quiet splash oem-config/enable=true ---

なおこれらをやらなくても、起動時に下記をやるとOK
タイミングが約3秒と厳しく下手するとやり直しになる方法
nVidiaのGPU搭載PCにUbuntuを入れようとしてハマった - Qiita
起動時に黒画面で即eを押した後 quiet splashをnomodesetに書き換えてF10をおせばできる

quiet splashってなに?ってのはこちら
boot - What do the nomodeset, quiet and splash kernel parameters mean? - Ask Ubuntu

Windowsをリカバリーモードで再起動してUSBから起動

詳細は割愛しますが、USBから起動してもいいし、いったんBIOSのデバイスのBoot順を変更してやってもいいかもしれません。
ただ、再起動のタイミングによってなのか、USBを選べない時がありますので、
BIOSのデバイスのBoot順をUSBを最初に持ってきましょう。

Try Ubuntu without installingを選ぶ

これを選ぶと難なくUbuntuの画面が表示されると思います。
これでダメな場合、何らかの対処が必要です。

データ消去を試みる

Ubuntuのファイラーを開いてOther Locationsを選択するとWindowsで使っていたドライブが/dev/nvme0n1p3とか/dev/sda2とかで見れると思います。
もしくはsudo fdisk -lで見れるかと思います。
あとはTerminalから

$ shred -v -n 3 -z /dev/nvme0n1p3

とやればデータを消せると思いますが、ここはまだ実施してません。

Ubuntuのインストール毎回ハマってる気がする…。

Linux Mintを使ってみた

試しに昔使ったことのあるLinux Mintはどうだろうということで、何も考えずに下記からISOをダウンロードしてインストールする。
Ubuntu 16.04ベースのLinux Mint 18.1 Sarahを使用
ISOをダウンロードしたらWindowsの標準機能で右クリックして、「ディスクイメージの書込み」を選ぶ。 DVD-Rに書き込んだ。 そして試しにUEFIモードでセキュアブートのままDVDから起動すると…
何事もなくライブDVDが立ち上がった。
これでいいんじゃないかと思った…。
ちなみに途中で2回ほどCUIでログインプロンプトが表示されますが、無視してたら勝手に処理が進っぽいです。
なんか入れないとだめかなと思って1回だけlogin: rootって打ち込んでしまいましたが。
ちなみにnouveauとか途中ででてくるのでGPUに対して何かしようってのはあるんだとおもいます。
f:id:fa11enprince:20200531042921p:plain
こんな感じでWindowsに寄せてます。


  1. これはMSIのBIOSの表記ではなくよくあるBIOSの表記です。

はてなブログからWordPress移行を検討するも結構厳しいことが判明した

f:id:fa11enprince:20200525002653j:plain docker-composeでWordPressをお試ししてみた記録です。
なんだかんだいってはてなブログいいよねっていう話です。

検証用としてCocoonというテーマとWP Githuber MDプラグインを使いました。 シンタックスハイライトができてなおかつ今に近いデザインということで、
テーマはCocoonを選び、マークダウンを使いたいのでWP Githuber MDというプラグインを導入しました。

環境構築

環境構築用ファイル 何はともあれローカル環境にDocker ComposeでWordPress環境を作ります。
次の2ファイル用意します。
uploads.ini

file_uploads = On
upload_max_filesize = 50M
post_max_size = 55M

uploads.iniを用意しないとデフォルトで少しのファイルしかアップロードできないため、
悲しいことになります。

docker-compose.yml

version: '3.6'

services:
   db:
     image: mysql:5.7
     container_name: mysql
     volumes:
       - db_data:/var/lib/mysql
     restart: unless-stopped
     environment:
       MYSQL_ROOT_PASSWORD: somewordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress

   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     container_name: wordpress
     ports:
       - "8000:80"
     restart: unless-stopped
     volumes:
       - ./html:/var/www/html
       - ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress
       WORDPRESS_DB_NAME: wordpress
volumes:
    db_data: {}

そしてこれらを置いたフォルダに移動して

docker-compose up -d

WordPress設定編

localhost:8000にアクセスして

言語設定: 日本語
に設定します。

テーマ

https://wp-cocoon.com/
すごい高機能です。見た目もいい感じだし。おすすめだと思います。

テーマのアップロード時FTPユーザを求められる

How to fix "WordPress Connection Information" on WP that is running in a docker container ? | DigitalOcean

wp-config.php

define('FS_METHOD','direct');

マウントしたフォルダが見えるので直接編集して、こいつを先頭に入れてあげます。

コードのシンタックスハイライト&Markdown

WordPressのcodeタグのCSS設定 | ハチアンアーカイブズ
これを入れてみます

以下はカスタマイズの作業メモです。

Cocoonのコード設定

コード
ハイライト表示  
    ソースコードをハイライト表示  
    行番号表示  
ハイライトスタイル  
  atom-one-light  

WP Githuber MD  
  こちらはデフォルトの設定のままとし、特にこちら側でシンタックスハイライトはしないようにします  

Cocoonのヘッダー

キャッチフレーズの配置  
  ヘッダーボトム  

Cocoonのソーシャルメディア

トップシェアボタン  
  トップシェアボタンの表示  
    メインカラムトップシェアボタンを表示 OFF  
  ボトムシェアボタン  
    Facebook/Line@をはずす  
  カラム数 4列  

外観 サイドバー

外観 > サイドバー  
  ウィジェットの追加  

その他

停止・削除  
  Akismet Anti-Spam  
  Hello Dolly  

記事移行編

ここからが本番です。

パーマリンク設定

カスタム構造

/entry/%year%/%monthnum%/%day%/%hour%%minute%%second%

注意: このURLは非推奨になったようです。そして5.4.1で動かなくなったとも
えええ、どうすりゃいいの…

構造は必ず %post_id% あるいは %postname% で終了し、各パーマリンクが個々の投稿を指すようにしてください (例 /%year%/%monthnum%/%day%/%postname%/ )。

wordpress 5.4.1 からの障害について | WordPress.org 日本語

これが絶望的にはてなブログからWordPressに移行できない理由です。
旧記事のURLをはてなブログ上で変更することはお勧めできません。 初めてはてなブログで大きな文字使いましたw

インポート

Movable Type・TypePad インポートツール

移行が成功するもコードのインデントがすべて消える…。

const socketio = require('socket.io');

function chat(server) {
const sio = socketio.listen(server);
sio.on('connection', function(socket) {
socket.on('chat-message', function(msg) {
console.log('Send message to client');
sio.emit('chat-message', msg + '💛');
});
socket.on("disconnect", function() {
});
});
};

module.exports = chat;

↑このような感じになります。 これは手動で直すしかなさそうだ。
170記事程度あるので、これは無理だと判断。←解消法ありました。
このリンクにある通り、movabletype-importerプラグインを改造すれば、大丈夫そう。 PHP詳しくないから知らなかったけど、trimって空白以外指定できるんですね。 数ある移行記事の中で要点をまとめている素晴らしい記事です。 プラグインのコード読んだけど、こんなに短いんすなーと感心。なんだかんだでPHPは基礎教養な気がしてきたから勉強しよう。

記事のページが開かない問題

WrodPress 5.4.1とCocoon 2.1.5.4で発生
バージョンをさげないとなんでか記事ページではなくアーカイブページに飛ばされるようだ

https://ja.wordpress.org/download/releases/
5.2.6に落としてみる
→OK
こういう問題があると、WPやっぱり大変だなと思う。

はてなフォトライフ問題

画像について、ある意味はてなフォトライフを使い続けられるので、実はメリットかもしれません。

購読ブログを手軽に利用できない問題

これは私が個人的にはてなで行動くしている人のブログを読めないっていう…
単にはてな好きの人の個人的理由です。

まとめ

…というわけでやっぱりはてなブログはいいですよ! 私はこのブログに関しては当面、移行しません。メンテナンスフリーというのがいかに楽か
というのは大事な要素だと思います。
大事なことを書き忘れましたが、ブログの購読もあって、コミュニティみたいなのがあるので、
やっぱりこういうところは素晴らしいと思います。

ドメイン移行戦記

f:id:fa11enprince:20200515235243j:plain
独自ドメインに移行しました。
旧ドメイン:https://fa11enprince.hatenablog.com/
新ドメイン:https://gup.monster/

前は独自ドメインはサブドメインでしかできなかったそうなのですが、
いつの間にかネイキッドドメインがOKになってるそうなので、wwwなしのネイキッドドメインで運用します。
サブドメインでは新規分はGoogle AdSenseが申請を受け付けてくれません。
自動で元のURLからリダイレクトしてくれるので素晴らしいです。

ここの記事に従って作業すれば終わりです。 以下、作業の記録です。1か所ハマりポイントがあります(謎のリダイレクト問題)。

ドメイン移行作業

Aレコードを作成

Aレコードで

13.230.115.161
13.115.18.61

を設定 サブドメインではないのでCNAMEの設定は不要です。

はてなブログの独自ドメインの設定

「独自ドメインの設定」をします。
入力後…10分くらい待たないとエラーと表示されます。
とりあえずは待てばOKなのです。数分すると「有効」となりエラーが消えます。
あと、時間があまりたってないと新URLのhttps証明書がエラーになってたりします(ちょっと待てば大丈夫)。

謎のリダイレクト問題1

新URLhttps://gup.monsterにアクセスすると
元のURLhttps://fa11enprince.hatenablog.comに飛ばされる…。

なんじゃこりゃ…と思ってググるとここが見つかる。
いったん「独自ドメインを設定」を空欄にして保存、再度ドメインを入力すると、OKになる。

URLの修正

JavaScriptでrssフィードを利用しているところがあって
rssフィードのURLの修正が必要でした。
あとは上部の自作メニューで

https://[旧URL]/archive/category/Programming

としていたところを

/archive/category/Programming

としました。

Google Analytics

以下2点を変更すればOK
1. プロパティの設定、デフォルトURL 2. ビューの設定、ウェブサイトのURL

ドメイン移行後の作業

ここからが長い戦いです。アクセス回復を見守りつつ、AdSenseを再度申請してみました。

Google AdSense

サイト追加で申請しなおします。
審査完了後のドメイン変更 - AdSense Community

旧アナリティクスコードをいったん消します。 承認が終わると一斉に貼りかえます。
と思ったのですが、その必要がなかった…戻したはいいもののエラーが…
これもしばらく待ってみます。 data-ad-clientが当然同じユーザなので一緒。サイト毎にコードが違うってわけでないです。
これは単に審査が通ってないから表示されていないのです。

Google AdSense 1回目の審査

2020/05/18 予想通り審査に落ちる。
広告が表示されないのはGoogleに承認されていないからです。403エラーが広告で発生すると思います。
ちなみにですが、このブログは、独自ドメインにする前は「はてなブログPro」で「はてなのサブドメイン」で運用していました。
Google AdSenseの審査に通っていました。その当時は2016年くらいで、
審査の基準もゆるくかつまだhttpしか対応していなかったのでかなり簡単でした。

サイトの停止または利用不可

お客様のサイトで複数のポリシー違反が確認されたため、サイトに広告を表示できない状態です。

理由としては「サイトの停止または利用不可」とのこと。

ということでむりやり検索エンジンに存在を知らせる
https://www.paradisia.jp/entry/2019/04/21/183223

「サイトの停止または利用不可」とのこと。他のブログを読むと、Googleのサーチボットにサイトが認識されていないことに気がつく。Google アナリティクスと、Googleサーチ・コンソールにサイトを登録し

と書いてあるので、サイトをSearch Consoleに登録してみる
ついでにsitemap.xmlを登録する
って…
https://support.google.com/webmasters/thread/4498538?hl=ja
https://support.google.com/webmasters/thread/3717131?hl=ja
むむむ…登録できない

これ最近の話だ。
https://support.google.com/webmasters/thread/44339439?hl=ja
ひとまず放置

サイトは広告を表示できない状態です

サイト上にコードが見つかりませんでした。これは、コードが不足しているか不完全である、またはサイトの URL が正しくないことが原因です。

えええ。そんなことはない。そもそもクローラーからみてサイトが見つかってないのが原因と思われる。

Google AdSense 2回目の審査

2020/05/21に2回目の申請をしてみました。
しかしSearch Consoleの様子を見てると、微妙な感じです。全然新URLがインデックスされていない…。
2020/05/26に不合格の通知が来ました。やっぱりか。

Google AdSense 3回目の審査

2020/05/27 3回目の審査をしてみました。
Search Consoleでクロール指示をしたり悪あがき再びです。
なんでか「アドレス変更」は使えないので、地道にインデックスされるようにします。
2020/06/03 3回目の不合格を受け取る。

不合格の理由に「サイトの停止または利用不可」はなくなり、 「価値の低い広告枠: コンテンツが存在しない」だけになり、その中の理由が「価値の低い広告枠: コンテンツが存在しない」に変わりました。
しばらくたってGoogleのクローラーが新ドメインを認識し始めたのだと思われます。
新ドメイン側がほぼインデックスされてない状況で、
おそらくまだ一部の記事が旧ドメイン側のでインデックスされているのだと思われますので、
Search Consoleで粘るか、さらにまだ待つ必要がありそうです。
タイトルで記事を検索した時に旧ドメインが出たり、 site:https://gup.monster/ で探したときに、全然でないか、Search Consoleのカバレッジを見たときに全然サイトのURLが集まってない感じなのが原因でしょうか。

記事を削除してから審査というのがあるのですが、それは本末転倒な感じがするのでしません。
ここまでくれば、あとは時間の問題な気がしています。

この記事が本質的な対策をしていました。
文字数とかでなくて、オリジナリティとかでもなくて、単に、
そもそもちゃんとした記事のページがGoogleインデックスされてないって話だと思います。

なぜこんなに苦労するかというと、一つにはなかなかサイトマップを認識できないからなのかなとも思ってます。

アドセンスについては、アクセス状況が改善するまで、
気長に1年がかりくらいで申請しようと思います。 …と思ったらドメインを移行して1か月半にして合格しました。

Google AdSense 4回目の審査

ある程度クローラーが認識してくれたと思うので、
修正したよってのにチェックをつけて再度審査を依頼してみました。
2020/06/26 Search Consoleで移行作業的な頑張りが功を奏したのか合格しました。
それより問題なのはアクセス戻ってない。さらに新ドメインでサイトマップ登録できてない…。

Search Console使って頑張る編

Search Consoleを使って対策します。

クローラー対策

2020/06/06 アクセスが3割くらい減ってきたので悪あがき。 過去のURLでサーチコンソールに登録して、カバレッジで有効になっているURLを個別にみます。
このとき旧URLのままになっているはずなので、「公開テスト」します。
そうするとクロールしてくれて、リダイレクトされているので新URLに変わるので、ここで
「インデックス登録をリクエスト」をひたすら1日の上限まで繰り返すと効率がいいのかも。

サイトマップ登録チャレンジ1回目

サーチコンソールで旧URLを登録してみる。
とりあえずこっちも頑張って新ドメインと並行で、「URLを検査」し、
インデックス登録をリクエスト

アドレス変更をやってみる

URLプレフィックスより旧URL登録 設定 > アドレス変更で最新のURLを入力 としたところ、この現象に遭遇… 確認エラー
「1件以上の必須テストに失敗しました。リクエストを続行できません」

ホームページからの 301 リダイレクト ページを取得できませんでした

うーむ、SEOは強いのに、ことごとくGoogleと相性悪いような(;´Д`)。
https://support.google.com/webmasters/thread/16572782?hl=ja

サイトマップ登録チャレンジ2回目

サイトマップの場所はクローラーが必ず参照する/robots.txtに書かれています。 ここのサイトの場合であれば、
https://gup.monster/robots.txt
です。ここにsitemap_index.xmlが記載されているのですが、
ふと何気にこれを旧ドメインのサーチコンソール
(つまりはてなのドメインだったほう)に投入したところ、なぜか成功しました。しかし0のまま。
ところで、ここの構造は何度か変わっているそうですが、今だと

sitemap_common.xml
sitemap_periodical.xml?year=2020&month=6
sitemap_periodical.xml?year=2020&month=5
...
sitemap_periodical.xml?year=2012&month=1

のように並んでいます。
このsitemap_periodical.xmlに個別の記事の個別、たとえば、
https://gup.monster/entry/2020/06/05/033013
のようなURLが並んでいる構造です。

これ個別に登録すればいいんじゃ?と思い至り、 先頭の1つ目の2020年6月分、
sitemap_periodical.xml?year=2020&month=6 を登録…。すると成功し、件数も出てきました。

どうもGoogle側では旧ドメインのURLでないとうまくいかず、 新ドメインのほうでやるとなぜか確実に失敗するようです。 リダイレクトしてるし、そもそもsitemap内に書かれているURLは新URLなので全部突っ込んであげようと。 ちょっとコピペが面倒なので、このサイトのスクリプトを使い省力化 すると、全部成功するではありませんか(登録して1秒程度は失敗のままですがすぐ成功します)。
f:id:fa11enprince:20200606014420p:plain
厳密にいうと、/aboutとか固定ページ等があるsitemap_common.xmlだけ失敗しますが…。←30分後に成功していました。

ダメもとでこの状態でアドレス変更を試みる

さんざん失敗した「アドレス変更」がこのおかげなのか成功しました。
f:id:fa11enprince:20200606021321p:plain
この機能は少なくとも半年間持続するとのこと。

Search Console を使用してアドレス変更リクエストを送信すると、元のサイトをクロールすることよりも、新しいサイトをクロールしてインデックス登録することを重視するよう、Google に通知されます。また、元のサイトから新しいサイトにさまざまなシグナルが転送され、正規ページを判断する際に、元のサイトよりも新しいサイトが優先されます。このようなアクションは、Search Console で移行を開始してから 180 日間続きます。 https://support.google.com/webmasters/answer/9370220?hl=ja
あとで気づいたのですが、「アドレス変更」ができたら1週間後あたりには旧ドメインからサイトマップを消し去ったほうがスムーズに新URLに移行できるのではないかとおもっています。ただ、地道に正しい新URLを教えてあげる必要はありそう。

サイトマップ登録チャレンジ3回目

旧ドメインのほうのサイトマップはもう大丈夫なのですが、
新ドメインに変更して5週目にして
新ドメインのほうは一つもサイトマップが登録できず。

旧ドメインのURLのサイトマップ登録を消す

2020/06/22 なかなか旧ドメインのURLでのアクセスが減らないのでサイトマップの登録を外す。 外してから2日後くらいから旧ドメインのアクセスがほぼ0になる。

独自ドメイン移行後の経過

独自ドメインに移行してからGoogleからの検索流入の状況についてザックリ記載したいと思います。ちなみにBingのほうはほぼ変化がありません。

1~9週目のアクセス状況

見事に下がって停滞しています。
5週目の時点で旧ドメインのサイトマップを削除しました。
それ以降一気にアクセスが下がり、すぐに旧ドメインへのアクセスがなくなりました。
そしていまだに新ドメインのサイトマップがなぜか全く登録できません。
元の10分の1にまで低下しています。
f:id:fa11enprince:20200717190021p:plain

JavaScriptで静的変数

f:id:fa11enprince:20200513231943j:plain 例えば次のような処理を考えてみます。
名前と身長と体重を与えると、その人のBMIがメソッドにより出力されるというものです。
さらに、食料foodNumがあって、食べると1つ減って、
代わりに1kg増えるものとします。食料はあらかじめ、貯蔵量に限界があって、減る一方とします。
一人の人のを都度処理するなら下記のような感じで書くと思います。
Vueとか使ってるとよく使うオブジェクトリテラルっす。

// 小数第N位で四捨五入
function roundFloat(number, n) {
    var _pow = Math.pow(10 , n);
    return Math.round(number * _pow) / _pow;
}
(function() {
    // Object Literal
    var person = {
        name: 'Bob',
        height: 180,
        weight: 65,
        foodNum: 10,  // classにしたときにこれを静的変数にしたい…
        bmi: function() {
            if (!this.height || !this.weight) {
                return 0;
            }
            return roundFloat(this.weight / Math.pow(this.height / 100, 2), 2);
        },
        show: function() {
            console.log('name: ' + this.name + ", bmi: " + this.bmi() + ", foodNum: " + this.foodNum);
        },
        eat: function() {
            if (this.foodNum != 0) {
                this.foodNum--;
                this.weight += 1;
            }
        }
    };
    person.show();
    person.eat();
    person.show();
})();

出力結果はこんな感じです

name: Bob, bmi: 20.06, foodNum: 10
name: Bob, bmi: 20.37, foodNum: 9

ただ、複数人のを一度に処理したいときにclass化してかつ、foodNumは共有資源で誰かが食べると、
みんなの分が減るものとします(なんか怖いですが)。
そうした時に、global変数以外では静的変数にしたくなります。
しかし、JavaScriptには静的変数がありません…。というのでこうやってしまおう!というもの。

ES5版

function roundFloat(number, n) {
    var _pow = Math.pow(10 , n);
    return Math.round(number * _pow) / _pow;
}
(function() {
    // Class
    var Person = function(name, height, weight) {
        if (!(this instanceof Person)) {
            return new Person(name, height, weight);
        }
        this.name = name;
        this.height = height;
        this.weight = weight;
    };
    Person.prototype.bmi = function() {
        if (!this.height || !this.weight) {
            return 0;
        }
        return roundFloat(this.weight / Math.pow(this.height / 100, 2), 2);
    };
    Person.prototype.show = function() {
        console.log('name: ' + this.name + ", bmi: " + this.bmi() + ", foodNum: " + Person.foodNum);
    };
    Person.prototype.eat = function() {
        if (Person.foodNum && Person.foodNum != 0) {
            Person.foodNum--;
            this.weight += 1;
        }
    }
    Person.foodNum = 10;  // static variable

    var person1 = new Person('Bob', 180, 65);
    person1.show();
    person1.eat();
    person1.show();
    var person2 = new Person('Alice', 170, 50);
    person2.show();
    person2.eat();
    person2.show();
})();

出力結果

name: Bob, bmi : 20.06, foodNum: 10
name: Bob, bmi : 20.37, foodNum: 9
name: Alice, bmi : 17.3, foodNum: 9
name: Alice, bmi : 17.65, foodNum: 8

Person.foodNumと単にオブジェクトにプロパティを設定してあげているのがポイントです。 JavaScriptっぽいですね。JavaScriptに慣れてない人はなんだこの変態文法と思うはずです。
そんな人はES2015版を見てもらえばいいかもしれません。ただし、実運用で使う場合はBabelを忘れずに…。

ES2015版

const roundFloat = (number, n) => {
    const _pow = Math.pow( 10 , n );
    return Math.round( number * _pow ) / _pow;
}
(() => {
    // ES2015 Class
    class Person {
        constructor(name, height, weight) {
            this.name = name;
            this.height = height;
            this.weight = weight;
        }
        static foodNum = 10;  // static variable
        bmi() {
            if (!this.height || !this.weight) {
                return 0;
            }
            return roundFloat(this.weight / Math.pow(this.height / 100, 2), 2);
        }
        show() {
            console.log(`name: ${this.name}, bmi : ${this.bmi()}, foodNum: ${Person.foodNum}`);
        }
        eat() {
            if (Person.foodNum != 0) {
                Person.foodNum--;
                this.weight += 1;
            }
        }
    }
    const person1 = new Person('Bob', 180, 65);
    person1.show();
    person1.eat();
    person1.show();
    const person2 = new Person('Alice', 170, 50);
    person2.show();
    person2.eat();
    person2.show();
})();

さっきと同じです。ES5版のSyntax Sugarっすね。Java/C#っぽくなりました。TypeScriptだとなお近くなります。

ぼやき

JavaScriptとNode力が足りないのでたまにES5で書くとthis.hoge = function() {}と書かねばならないところを、
var foo = function() {}とやって自爆しまう雑魚でした。
ECMAScript 6 compatibility table を見ると、もう最近はIEを捨てると、ちょっとしたJSを書くときではBabeらずにES2015で書いてしまってもいいかもしれない…と思った。 JSの辛いところは古くからあるライブラリはやはりES5以前の知識が必須なところですかね。

参考リンク

Static variables in JavaScript - Stack Overflow