容器化部署博客【1】——部署我的博客

date: 2023-11-13 update slug: docker_deploy_blog_1 key: Docker ref: https://blognas.hwb0307.com/linux/docker/485 cover:

Ucloud, install system

# 使用的是ubuntu22.04

# 在ubuntu用户下切换到root用户
sudo su
# 对root用户重写root密码
passwd

Add users

2023-11-5

# adduser是一个系统自带的perl脚本,一键式配置新用户
# 而useradd是一个系统内建命令,功能比较简陋

adduser zhaohuanan

Core dependency

2023-11-5

docker

# install docker on ubuntu22
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Add the repository to Apt sources:
echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

# Install the Docker packages. 
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-compose
# Verify that the Docker Engine installation is successful by running the hello-world image
sudo docker run hello-world
# if you wanna uninstall docker
# see https://docs.docker.com/engine/install/ubuntu/



# [添加用户到docker组]
## [Docker用户组]在安装Docker时,会自动创建一个名为docker的用户组。只有属于docker用户组的用户才能使用Docker命令,而不需要使用sudo命令或者以root用户身份登录。因此,如果想要让某个用户能够方便地使用Docker,可以将其添加到docker用户组中。
## [将用户添加到docker组]要将用户添加到docker组,可以按照以下步骤进行操作:如果该命令返回类似的输出,表示docker组已存在
grep docker /etc/group
docker:x:999:
## [创建docker组(可选)]如果步骤1中未找到docker组,可以运行以下命令创建docker组
sudo groupadd docker
## [将用户添加到docker组]运行以下命令将指定用户添加到docker组中
sudo usermod -aG docker username
## [重新登录用户]为了使修改生效,需要重新登录要添加到docker组的用户。可以使用以下命令注销并重新登录
exit
# [验证用户是否已添加到docker组]
## [步骤1:登录用户]使用已添加到docker组的用户登录系统。
## [步骤2:运行Docker命令]运行以下Docker命令,查看是否能够正常执行:
su zhaohuanan
docker run hello-world  # 直到看到Hello from Docker!

net-tools

# su
apt install net-tools

zip

# su
apt install zip
# zip unzip

My terminal settings

2023-11-05

install zsh

# install zsh; su or su ubuntu
su
apt install zsh

install rust

# 安装rust
su zhaohuanan
# 下一步遇到问题看这个https://www.sunzhongwei.com/install-rust-with-china-mirror
# 设置一下镜像即可
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
# 选2
Default host triple? [x86_64-unknown-linux-gnu]
Default toolchain? (stable/beta/nightly/none) [stable]
Profile (which tools and data to install)? (minimal/default/complete) [default]
Modify PATH variable? (Y/n)
# n!!!

# 只有PATH不选默,其他默认回车即可
# 输入完n之后返回上个界面,直接敲回车进入安装

install oh-my-zsh

# su zhaohuanan
# 切换默认shell为zsh
chsh -s /usr/bin/zsh

# 安装oh-my-zsh
sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
# 按照必备插件
cd ~/.oh-my-zsh/custom/plugins/
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git
git clone https://github.com/zsh-users/zsh-autosuggestions

install .my_shell_envs

git clone git@github.com:hermanzhaozzzz/.my_shell_envs.git
cd .my_shell_envs/
bash deploying_locally.sh

## 遇到报错make: command not found
## su ubuntu
# sudo apt-get update
# sudo apt-get install g++ gcc automake autoconf libtool make
# su zhaohuanan
# cd
# cd .my_shell_envs/
# bash deploying_locally.sh

# 顺利完成提示source
source ~/.zshrc
conda install exa bat

deploy my blog via docker

2023-11-05

step 01 准备镜像

项目部署需要3个基础镜像外加一个izone的构建镜像(可以自己拉取代码构建,不过这里推荐拉取我构建好的镜像),拉取镜像的命令:

# 3个基础镜像
docker pull nginx
docker pull redis
docker pull mysql:5.7
# 1个自构建镜像,这个tag表示19年7月构建,项目是第3代,镜像对应的编排版本也使用这个tag,后续会说到
docker pull registry.cn-shenzhen.aliyuncs.com/tendcode/izone:3.19.7

step 02 拉取镜像代码

为了避免挂载目录权限问题,后续命令全部使用root账号执行!!! !!!其实我没遇到这个问题,后续我全部用zhaohuanan这个普通账号执行 拉取代码,直接拉取跟镜像的tag一样的项目tag:

# pwd
# /home/zhaohuanan/3.project
su
git clone git@github.com:hermanzhaozzzz/my-blog-izone-docker.git

step 03 创建环境变量文件

项目依赖两个环境变量文件,必须创建,第一个文件是 .env,这个文件是docker-compose 默认使用的环境变量问题,可以把参数传递到 docker-compose 中。进入izone-docker 目录,创建两个问题,文件内容如下:

# .env

# db
MYSQL_IMAGE=mysql:5.7
MYSQL_ROOT_PASSWORD=1314520@abc

# redis
REDIS_IMAGE=redis

# web
IZONE_IMAGE=registry.cn-shenzhen.aliyuncs.com/tendcode/izone:3.19.7
IZONE_MYSQL_NAME=izone

# nginx
NGINX_IMAGE=nginx

然后创建一个 izone.env 文件,这个里面的环境变量都会传递给 izone 使用,至于izone 可以设置哪些环境变量,可以去 izone 项目的 settings 文件中查看。这里可以虽然传入几个变量(其实可以一个也不传,因为环境变量不传的时候有默认值使用):

# izone.env

# https://github.com/Hopetree/izone/blob/master/izone/settings.py

#######################################
# SECURITY WARNING: keep the secret key used in production secret!
IZONE_SECRET_KEY=#!kta!9e0)24p@9#=*=ra$r!0k0+p5@w+a%7g1bboo9+9080
#######################################
# 应用配置及DEBUG
#######################################
# 是否开启[在线工具]应用
IZONE_TOOL_FLAG=True
# 是否开启[API]应用
IZONE_API_FLAG=True
# 不要在生产环境中开启
IZONE_DEBUG=True
#######################################
# 站点基本信息
#######################################
IZONE_LOGO_NAME=华男菌爱学习
IZONE_SITE_END_TITLE=赵华男的博客
IZONE_SITE_DESCRIPTION=我叫赵华男,是一名科研工作者,主要研究基因编辑和生物信息学相关问题,这个站点是我日常记笔记学习的地方
IZONE_SITE_KEYWORDS=赵华男,清华大学,北京大学,生物信息,基因编辑,CRISPR,数据科学,Python,个人博客
IZONE_SITE_CREATE_DATE='2023-11-05'
IZONE_GITHUB=https://github.com/hermanzhaozzzz

# 个人外链信息(导航栏下拉中显示)
IZONE_PRIVATE_LINKS=https://www.zhihu.com/people/hymanzhaozzzz,https://www.xiaohongshu.com/user/profile/61ac514e000000001000a356

#######################################
# 站点底部信息
#######################################
# 网站备案信息
# IZONE_BEIAN
# 站长统计(友盟)
# IZONE_CNZZ_PROTOCOL=
# 站长统计(51.la)
# IZONE_LA51_PROTOCOL
# 站长推送
# IZONE_SITE_VERIFICATION=''
# 使用 http 还是 https (sitemap 中的链接可以体现出来)
IZONE_PROTOCOL_HTTPS=HTTPS
#######################################
# 邮箱配置(站点用邮箱)
#######################################
IZONE_EMAIL_HOST=smtp.163.com
IZONE_EMAIL_HOST_USER=hermanzhaozzzz@163.com
# 这个不是邮箱密码,而是授权码
IZONE_EMAIL_HOST_PASSWORD=163的设备授权码

# 由于阿里云的25端口打不开,所以必须使用SSL然后改用465端口
IZONE_EMAIL_PORT=465
IZONE_EMAIL_USE_SSL=True


# 网站管理后台默认发件人
# 不设置的话django默认使用的webmaster@localhost
# 所以要设置成自己可用的邮箱
IZONE_DEFAULT_FROM_EMAIL=华男菌的博客 <hermanzhaozzzz@163.com>

# 注册中邮件验证方法:
#   “强制(mandatory)”,
#   “可选(optional)【默认】”
#   “否(none)”
# 开启邮箱验证的话,如果邮箱配置不可用会报错,所以默认关闭,根据需要自行开启
IZONE_ACCOUNT_EMAIL_VERIFICATION=optional

#######################################
# 邮箱配置(管理员用邮箱)
#######################################
# 格式:name|test@test.com 多组用户用英文逗号隔开
# 服务出现故障会收到到邮件,环境变量值的格式:name|test@test.com
# 多组用户用英文逗号隔开
IZONE_ADMIN_EMAIL_USER=hermanzhaozzzz|hermanzhaozzzz@gmail.com

两个文件创建成功之后可以检查一下文件是合格,执行命令:

docker-compose config

step 04 修改nginx配置

由于项目默认给的nginx配置是我自己项目的,所以不适合其他人使用,这里把项目代码中nginx/conf.d/ 目录中的配置文件全部删除,然后在nginx/conf.d/ 目录中创建一个通用的配置(使用 localhost):

cd nginx/conf.d && rm -f server_izone.conf
vi default.conf

default.conf 的内容如下:

server {
    # 端口和域名
    listen 80;
    server_name localhost;

    # static  media 的地址
    location /static/ {
        root /opt/izone;
    }
    location /media/ {
        root /opt/izone;
    }

    # web 服务使用80端口,并且添加别名跟本地域名保持一致
    location / {
        proxy_pass http://web:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # 其他配置
    client_max_body_size 1m;
    client_header_buffer_size 128k;
    client_body_buffer_size 1m;
    proxy_buffer_size 32k;
    proxy_buffers 64 32k;
    proxy_busy_buffers_size 1m;
    proxy_temp_file_write_size 512k;
}

我的配置

proxy_cache_path /tmp/cache levels=1:2 keys_zone=mycache:100m inactive=1d max_size=10g;

server {
    # 端口和域名
    listen 443 ssl;
    server_name zhaohuanan.cc;
    ssl_certificate /etc/nginx/ssl_cert/zhaohuanan.cc.pem;
    ssl_certificate_key /etc/nginx/ssl_cert/zhaohuanan.cc.key;
    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout 5m;
    # 自定义设置使用的TLS协议的类型以及加密套件
    #(以下为配置示例,请您自行评估是否需要配置)
    # TLS协议版本越高,HTTPS通信的安全性越高
    # 但是相较于低版本TLS协议,高版本TLS协议对浏览器的兼容性较差
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    # 表示优先使用服务端加密套件。默认开启
    ssl_prefer_server_ciphers on;


    # static  media 的地址,添加缓存
    location /static/ {
        root /opt/izone;
        proxy_cache mycache;
        expires 30d;
    }

    location /media/ {
        root /opt/izone;
        proxy_cache mycache;
        expires 30d;
    }

    # web 服务转发,端口需要一致
    location / {
        proxy_pass http://web:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

#    # 图床映射,添加自己的图床地址即可
#    location ^~ /cdn/ {
#        proxy_pass http://pic.zhaohuanan.cc/;
#        proxy_cache mycache;
#        expires 30d;
#    }

    # 其他配置
    client_max_body_size 1m;
    client_header_buffer_size 128k;
    client_body_buffer_size 1m;
    proxy_buffer_size 32k;
    proxy_buffers 64 32k;
    proxy_busy_buffers_size 1m;
    proxy_temp_file_write_size 512k;
}

# http 跳转到 https
server {
    listen 80;
    # 填写证书绑定的域名
    server_name zhaohuanan.cc;
    # 将所有HTTP请求通过rewrite指令重定向到HTTPS
    rewrite ^(.*) https://$server_name$1 permanent;
}

step 05 部署容器

退回到 izone-docker 目录,启动容器的命令(加 -d 是后台运行),可以看到输出:

# 代码仓库与静态文件解耦

PFILES=/home/zhaohuanan/3.project/my-blog_zhaohuanan.cc/pricvate_files
IZONEFILES=/home/zhaohuanan/3.project/my-blog_zhaohuanan.cc/my-blog-izone-docker
ln -s $PFILES/izone.env $IZONEFILES/izone.env
ln -s $PFILES/izone_docker_compose.env $IZONEFILES/.env
cp $PFILES/zhaohuanan.cc.key $IZONEFILES/nginx/ssl_cert
cp $PFILES/zhaohuanan.cc.pem $IZONEFILES/nginx/ssl_cert
[root@CentOS-2 izone-docker]# docker-compose up -d
Creating network "izone-docker_frontend" with driver "bridge"
Creating network "izone-docker_backend" with driver "bridge"
Creating izone_redis ... done
Creating izone_db    ... done
Creating izone_web   ... done
Creating izone_nginx ... done

# 此时可以看到容器运行的输出,此时的容器已经运行了,但是数据还没有初始化

然后可以查看一下容器运行状态,如果都是up 就没问题:

[root@CentOS-2 izone-docker]# docker-compose ps
   Name                  Command               State                    Ports
-----------------------------------------------------------------------------------------------
izone_db      docker-entrypoint.sh mysqld      Up      3306/tcp, 33060/tcp
izone_nginx   nginx -g daemon off;             Up      0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
izone_redis   docker-entrypoint.sh redis ...   Up      6379/tcp
izone_web     gunicorn izone.wsgi -b 0.0 ...   Up

step 06 初始化数据库

虽然容器都起来了,但是izone 项目的数据库里面是空的,所以要先初始化一下数据库,直接在izone-docker 目录下执行如下命令:

# !!!如果不改Django的源代码,理论上执行一次就行

# 一条一条的输入
# 初始化数据
docker exec -it izone_web python manage.py makemigrations
docker exec -it izone_web python manage.py migrate
# 收集静态文件
docker exec -it izone_web python manage.py collectstatic
# 初始化搜索索引
docker exec -it izone_web python manage.py update_index
# 创建管理员账号
docker exec -it izone_web python manage.py createsuperuser

step 07 重启服务,浏览页面

在izone-docker 目录下,依次执行关闭和启动命令,重启服务:

[root@CentOS-2 izone-docker]# docker-compose down
Stopping izone_nginx ... done
Stopping izone_web   ... done
Stopping izone_redis ... done
Stopping izone_db    ... done
Removing izone_nginx ... done
Removing izone_web   ... done
Removing izone_redis ... done
Removing izone_db    ... done
Removing network izone-docker_frontend
Removing network izone-docker_backend
[root@CentOS-2 izone-docker]# docker-compose up -d
Creating network "izone-docker_frontend" with driver "bridge"
Creating network "izone-docker_backend" with driver "bridge"
Creating izone_redis ... done
Creating izone_db    ... done
Creating izone_web   ... done
Creating izone_nginx ... done

浏览器输入服务器(或者虚拟机)的IP地址查看页面是否正常,也可以在服务器使用curl 命令访问:

curl http://localhost

浏览器效果

update my blog

平台的升级是只izone项目代码有更新,需要将更新的内容升级到平台的部署环境的操作。这里可以将更新的内容分为几种类型,每种类型需要进行的操作稍微不同。

只涉及逻辑更新

只涉及逻辑代码的更新是只项目的更新只有一些模板、视图、URL等逻辑的变动,这种更新只需要重新构建镜像然后重新启动izone容器即可,具体操作参考:

构建镜像的操作就不再重复描述了,这里说一下如何使用新镜像重新启动izone容器的操作,进入项目的启动目录izone-docker中,执行命令:

docker-compose restart web

涉及静态文件更新

如果涉及静态文件的变动,也就是css文件,ji文件和图片这些,那么除了重新构建镜像之外并且重新启动容器之外,还需要执行静态文件收集

docker-compose restart web
docker-compose run web python manage.py collectstatic

涉及模型变动

如果涉及模型的变动,除了重启容器服务,还需要进行数据迁移:

docker-compose restart web
docker-compose run web python manage.py migrate

涉及配置变更

如果项目的更新涉及到配置的变动,主要是指的izone.env的变动,则需要按照项目的更新模板izone.env.template来更新izone.env配置,然后重启容器即可。

migrate my blog via docker

上面的步骤足够完成新平台的搭建,如果涉及到平台的迁移,比如更换服务器,可以参考下面的步骤进行操作。

数据备份

平台需要备份的数据包括两部分:数据库,静态文件。

可以直接参考我的备份脚本,我一般的都是在平台上面设置成定时任务进行自动备份。

首先是静态文件备份脚本:

#!/bin/bash

# crontab -e
# 0 05 * * * sh /home/zhaohuanan/3.project/my-blog_zhaohuanan.cc/scripts/backup_media.sh

input_dir=/home/zhaohuanan/3.project/my-blog_zhaohuanan.cc/my-blog-izone-docker/web
backup_dir=/home/zhaohuanan/3.project/my-blog_zhaohuanan.cc/backup
maxnum=15
backup_name=media_$(date +'%Y%m%d_%H%M%S').zip

# 备份 media 目录到指定目录
cd $input_dir
zip -r $backup_dir/$backup_name ./media

function check_files()
{
    cd $backup_dir
    local file_lis=$(ls | grep media.*zip)
    for file in ${file_lis[@]}
    do
        num=$(ls | grep media.*zip | wc -l)
        if [[ $num -lt $maxnum ]]; then
            break
        else
            rm -f $file && echo "remove ${file}"
        fi
    done
    echo "$(ls)"
}

check_files

然后是数据库备份脚本:

#!/bin/bash

# crontab -e
# 0 05 * * * sh /home/zhaohuanan/3.project/my-blog_zhaohuanan.cc/scripts/backup_mysql.sh

backup_dir=/home/zhaohuanan/3.project/my-blog_zhaohuanan.cc/backup
backup_name=izone_$(date +'%Y%m%d_%H%M%S').sql
maxnum=15
db_name=izone_db

# 执行 db 容器的备份命令
docker exec $db_name sh -c 'exec mysqldump -uroot -p$MYSQL_ROOT_PASSWORD $MYSQL_DATABASE' > ${backup_dir}/${backup_name}
[[ $? -eq 0 ]] && echo "backup $backup_name successfully." || echo "backup $backup_name failed."

# 检查备份文件数量,如果多余最大保存数量,就删除多余的备份
function check_files()
{
    cd $backup_dir
    local file_lis=$(ls | grep izone.*sql)
    for file in ${file_lis[@]}
    do
        num=$(ls | grep izone.*sql | wc -l)
        if [[ $num -lt $maxnum ]]; then
            break
        else
            rm -f $file && echo "remove ${file}"
        fi
    done
    echo "$(ls)"
}

check_files

拷贝备份数据

将备份数据拷贝到新的平台中,包括数据库备份和静态资源备份,还有项目的环境变量文件(.env和izone.env),这里只有izone.env是自定义的配置,所以只拷贝这个就行。当然,你也应该把备份脚本、Nginx配置等拷贝到新平台。

这里只说平台的备份文件:

(base) ╭─zhaohuanan at 10-60-228-183 in ~/3.project/my-blog_zhaohuanan.cc
╰─○ tree -L 1
.
├── backup  # 需要其他设备备份
├── my-blog-izone-docker # 需要GitHub代码备份
├── pricvate_files # 需要其他设备备份
└── scripts # 需要其他设备备份

数据还原

1、还原配置文件

izone.env文件覆盖项目的izone.env

mv -f izone.env

2、还原静态文件

执行还原命令,注意根据实际的目录修改命令:

unzip /root/media_20230918_050001.zip -d /home/zhaohuanan/3.project/my-blog_zhaohuanan.cc/my-blog-izone-docker/web

这个解压会把压缩包中的media目录解压到/root/izone-docker/web中的media,可以解压后查看验证。

3、还原数据库

首先将数据库备份文件复制到mysql容器中,直接放到/tmp目录下面即可:

docker cp /home/zhaohuanan/3.project/my-blog_zhaohuanan.cc/backup/izone_20230918_050001.sql izone_db:/tmp/

然后登录数据库容器:

docker exec -it izone_db bash

然后执行数据库还原命令:

mysql -uroot -p$MYSQL_ROOT_PASSWORD -D $MYSQL_DATABASE --default-character-set=utf8 < /tmp/izone_20230918_050001.sql

执行完成输入exit后退出容器即可。

以上几个命令的输入输出如下:

[root@zero-0 media]# docker cp /root/izone_20230918_050001.sql izone_db:/tmp/
Successfully copied 149MB to izone_db:/tmp/
[root@zero-0 media]# docker exec -it izone_db bash
bash-4.2# mysql -uroot -p$MYSQL_ROOT_PASSWORD -D $MYSQL_DATABASE --default-character-set=utf8 < /tmp/izone_20230918_050001.sqlmysql: [Warning] Using a password on the command line interface can be insecure.
bash-4.2# exit
exit
[root@zero-0 media]# 

更新资源

由于静态文件和数据都是导入的,所以需要在Django里面进行更新,执行静态资源收集和搜索索引更新命令:

docker exec -it izone_web python manage.py collectstatic
docker exec -it izone_web python manage.py update_index

然后进入izone-docker的项目中,重启容器:

docker-compose down
docker-compose up -d

输入输出如下:

[root@zero-0 izone-docker]# docker-compose down
/usr/lib/python2.7/site-packages/paramiko/transport.py:33: CryptographyDeprecationWarning: Python 2 is no longer supported by the Python core team. Support for it is now deprecated in cryptography, and will be removed in the next release.
  from cryptography.hazmat.backends import default_backend
Stopping izone_nginx ... done
Stopping izone_web   ... done
Stopping izone_db    ... done
Stopping izone_redis ... done
Removing izone_nginx ... done
Removing izone_web   ... done
Removing izone_db    ... done
Removing izone_redis ... done
Removing network izone-docker_frontend
Removing network izone-docker_backend
[root@zero-0 izone-docker]# docker-compose up -d
/usr/lib/python2.7/site-packages/paramiko/transport.py:33: CryptographyDeprecationWarning: Python 2 is no longer supported by the Python core team. Support for it is now deprecated in cryptography, and will be removed in the next release.
  from cryptography.hazmat.backends import default_backend
Creating network "izone-docker_frontend" with driver "bridge"
Creating network "izone-docker_backend" with driver "bridge"
Creating izone_db    ... done
Creating izone_redis ... done
Creating izone_web   ... done
Creating izone_nginx ... done

此时再访问一下网页端口看看效果,可以看到数据已经完美还原:

网站代码更新

docker container ls