Monotalk さんの以下の記事に触発されて、私が本番運用している某ブログサイトの Mezzanine を 4.1.0 から 4.2.2 にアップデートしてみました。
アップデートするのに結構苦労したように書いてあったので、念のため、Vagrant の開発環境と EC2 のバックアップイメージから起動したインスタンス上でのリハーサルをしてから臨みました。
結論から言うと、あまり苦労せずにアップデートできました。Monotalk さんは Mezzanine 3 系から運用していたような感じだったので、そこからの負債が溜まっていたのではないかと推測します。
アップデート手順
アップデートの手順はたったこれだけです。
$ pip install -U Mezzanine==4.2.2 $ python manage.py makemigrations $ python manage.py migrate
アップデート前の本番環境のインストール済みライブラリ一覧(2016/11/2 時点)
$ pip list awscli (1.11.10) beautifulsoup4 (4.5.1) bleach (1.4.3) boto (2.41.0) botocore (1.4.67) chardet (2.3.0) colorama (0.3.7) Django (1.9.9) django-appconf (1.0.2) django-compressor (2.0) django-contrib-comments (1.7.2) django-ses (0.8.0) docutils (0.12) filebrowser-safe (0.4.5) future (0.15.2) futures (3.0.5) grappelli-safe (0.4.4) gunicorn (19.6.0) html5lib (0.9999999) jmespath (0.9.0) Mezzanine (4.1.0) MySQL-python (1.2.5) oauthlib (1.1.2) Pillow (3.3.1) pip (8.1.2) psycopg2 (2.6.2) pyasn1 (0.1.9) python-dateutil (2.5.3) python-memcached (1.58) pytz (2016.6.1) rcssmin (1.0.6) requests (2.11.1) requests-oauthlib (0.6.2) rjsmin (1.0.12) rsa (3.4.2) s3transfer (0.1.9) setproctitle (1.1.10) setuptools (24.0.2) six (1.10.0) tzlocal (1.2.2) wheel (0.29.0)
アップデート後のインストール済みライブラリの一覧は、以下のようになりました。
$ pip list awscli (1.11.10) beautifulsoup4 (4.5.1) bleach (1.4.3) boto (2.41.0) botocore (1.4.67) chardet (2.3.0) colorama (0.3.7) Django (1.10.3) django-appconf (1.0.2) django-compressor (2.0) django-contrib-comments (1.7.3) django-ses (0.8.0) docutils (0.12) filebrowser-safe (0.4.6) future (0.16.0) futures (3.0.5) grappelli-safe (0.4.5) gunicorn (19.6.0) html5lib (0.9999999) jmespath (0.9.0) Mezzanine (4.2.2) MySQL-python (1.2.5) oauthlib (2.0.0) Pillow (3.4.2) pip (8.1.2) psycopg2 (2.6.2) pyasn1 (0.1.9) python-dateutil (2.5.3) python-memcached (1.58) pytz (2016.7) rcssmin (1.0.6) requests (2.11.1) requests-oauthlib (0.7.0) rjsmin (1.0.12) rsa (3.4.2) s3transfer (0.1.9) setproctitle (1.1.10) setuptools (24.0.2) six (1.10.0) tzlocal (1.3) wheel (0.29.0)
Mezzanine 4.1.0 から 4.2.2 への一番の変更点は、Django のバージョンが 1.9 系から 1.10 系にアップデートされることでしょうか。
4.1.0 から 4.2.2 への全ての変更箇所は以下で確認することができます。
https://github.com/stephenmcd/mezzanine/compare/4.1.0...4.2.2
このアップデートでいくつかのバグ(*1)が本家で修正されたのに伴い、技術的な負債を少し解消することができました。
影響
4.2.2 へのアップデート後、ping_google コマンド実行時にエラーが出るようになってしまいました。
$ python manage.py ping_google Traceback (most recent call last): File "manage.py", line 14, in <module> execute_from_command_line(sys.argv) File "/home/vagrant/.virtualenvs/akiyokoproject/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 367, in execute_from_command_line utility.execute() File "/home/vagrant/.virtualenvs/akiyokoproject/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 359, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "/home/vagrant/.virtualenvs/akiyokoproject/local/lib/python2.7/site-packages/django/core/management/base.py", line 294, in run_from_argv self.execute(*args, **cmd_options) File "/home/vagrant/.virtualenvs/akiyokoproject/local/lib/python2.7/site-packages/django/core/management/base.py", line 345, in execute output = self.handle(*args, **options) File "/home/vagrant/.virtualenvs/akiyokoproject/local/lib/python2.7/site-packages/django/contrib/sitemaps/management/commands/ping_google.py", line 12, in handle ping_google(sitemap_url=options['sitemap_url']) File "/home/vagrant/.virtualenvs/akiyokoproject/local/lib/python2.7/site-packages/django/contrib/sitemaps/__init__.py", line 36, in ping_google raise SitemapNotFound("You didn't provide a sitemap_url, and the sitemap URL couldn't be auto-detected.") django.contrib.sitemaps.SitemapNotFound: You didn't provide a sitemap_url, and the sitemap URL couldn't be auto-detected.
いろいろ調査したのですが、まだ解決していません。。
Django 本体の差分にも原因があるのかなぁ??
https://fossies.org/diffs/Django/1.9.8_vs_1.10/django/contrib/sitemaps/__init__.py-diff.html
バックアップイメージでの検証
EC2 のバックアップイメージから起動したインスタンス上でのリハーサル手順をメモしておきます。
1. バックアップイメージからインスタンス起動
まずは、EC2 インスタンスの Create Image をおこない、AMI を作成します。
作成したイメージからインスタンスを起動し、新たな Elastic IP を付与します。
2. settings.py の修正
config/local_settings.py
ALLOWED_HOSTS = ['akiyoko.com']
を、
ALLOWED_HOSTS = ['52.199.xx.xx']
と修正します(新しい IP アドレスを「52.199.xx.xx」と想定)。
最後に、プロセスを再起動。
$ sudo supervisorctl restart all
なおこれを修正しないと、アクセス時に Bad Request (400) が発生してしまいます。
(参考)django - Bad request 400: nginx / gunicorn - Stack Overflow
3. Nginx の設定ファイル修正
server_name に指定しているドメインを、Elastic IP に変更します。
また、テスト検証では HTTPS は使用しないので、SSL の設定は取り除きます。
/etc/nginx/sites-enabled/akiyokoproject.conf
(変更前)
server { #listen 80; listen 443 ssl; server_name akiyoko.com; client_max_body_size 10M; keepalive_timeout 15; error_log /home/webapp/logs/akiyokoproject_error_nginx.log info; ssl_certificate conf/akiyokoproject.crt; ssl_certificate_key conf/akiyokoproject.key; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA; ssl_prefer_server_ciphers on; # Deny illegal Host headers if ($host !~* ^(akiyoko.com)$) { return 444; } ・ ・ server { listen 80; server_name akiyoko.com; return 301 https://akiyoko.com$request_uri; } server { listen 80; listen 443 ssl; server_name www.akiyoko.com; return 301 https://akiyoko.com$request_uri; }
(変更後)
server { listen 80; # listen 443 ssl; server_name 52.199.xx.xx; client_max_body_size 10M; keepalive_timeout 15; error_log /home/webapp/logs/akiyokoproject_error_nginx.log info; #ssl_certificate conf/akiyokoproject.crt; #ssl_certificate_key conf/akiyokoproject.key; #ssl_session_cache shared:SSL:10m; #ssl_session_timeout 10m; #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA; #ssl_prefer_server_ciphers on; # Deny illegal Host headers if ($host !~* ^(52.199.xx.xx)$) { return 444; } ・ ・ #server { # listen 80; # server_name akiyoko.com; # return 301 https://akiyoko.com$request_uri; #} #server { # listen 80; # listen 443 ssl; # server_name www.akiyoko.com; # return 301 https://akiyoko.com$request_uri; #}
最後に Nginx をリロード。
$ sudo service nginx reload
4. Mezzanine アップデート
$ workon akiyokoproject (akiyokoproject)$ pip install -U Mezzanine==4.2.2 ・ ・ Successfully installed Mezzanine-4.2.2 django-1.10.3 django-contrib-comments-1.7.3 filebrowser-safe-0.4.6 future-0.16.0 grappelli-safe-0.4.5 oauthlib-2.0.0 pillow-3.4.2 pytz-2016.7 requests-oauthlib-0.7.0 tzlocal-1.3
(akiyokoproject)$ python manage.py makemigrations (akiyokoproject)$ python manage.py migrate
Mezzanine 系のモデル変更はありませんでしたが、Django 系の auth_user のモデルが少し変更になったようです。
$ sudo supervisorctl restart all
5. テンプレートの更新
HTMLファイル確認用の templats ディレクトリに、テンプレートの更新差分(4.1.0 → 4.2.2)をマージします。
config/settings.py
@@ -273,7 +275,7 @@ TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [ - os.path.join(PROJECT_ROOT, "custom/templates"), + #os.path.join(PROJECT_ROOT, "custom/templates"), os.path.join(PROJECT_ROOT, "templates") ], "APP_DIRS": True,
上記のように修正して、一時的にカスタムテンプレートを外してから、
$ python manage.py collecttemplates
を実行して、テンプレートを上書きします。
なお、上書きするときにいちいちオーバーライドするかどうか聞かれるので、
~/.virtualenvs/akiyokoproject/lib/python2.7/site-packages/mezzanine/core/management/commands/collecttemplates.py
self.stdout.write("Template exists%s.\n" % prev) #confirm = input("Overwrite? (yes/no/abort): ") #while confirm not in ("yes", "no", "abort"): # confirm = input( # "Please enter either 'yes', 'no' or 'abort': ") #if confirm == "abort": # self.stdout.write("Aborted\n") # break # exit templates copying loop #elif confirm == "no": # self.stdout.write("[Skipped]\n") # copy = False if copy: try: os.makedirs(os.path.dirname(dest)) except OSError: pass shutil.copy2(path, dest) template_src[name] = app count += 1 if verbosity >= 1: s = "s" if count != 1 else "" self.stdout.write("\nCopied %s template%s\n" % (count, s))
とコメントアウトすると、手間が省けます。
custom アプリケーションで独自に修正したテンプレートの一覧は以下の通りなので、
custom/__init__.py custom/static/css/custom.css custom/static/img/slide-1.jpg custom/static/img/slide-2.jpg custom/templates/base.html custom/templates/blog/blog_post_detail.html custom/templates/blog/blog_post_list.html custom/templates/generic/includes/comment.html custom/templates/generic/includes/comments.html custom/templates/includes/form_fields.html custom/templates/index.html custom/templates/pages/menus/dropdown.html custom/templates/twitter/tweets.html custom/templatetags/__init__.py custom/templatetags/add_attributes.py
本家テンプレートの更新差分(4.1.0 → 4.2.2)と重複したファイル
- blog/blog_post_detail.html
については手動でマージをおこない、その他の
- includes/editable_loader.html
- pages/form.html
- pages/menus/admin.html
については custom アプリケーションの templates ディレクトリ以下のものに上書きしました。