容器化部署博客【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