几天前在腾讯云买了个最低配置的服务器,开整!
先随便找个教程,简单入门了一下docker,然后在linux服务器上装好docker。心想,我在win10上也装个docker,生成镜像,上传到docker hub,去服务器拉下来直接跑就行。
开启Hyper-V -> 去官网下载安装包(官网链接) -> 安装包告诉我windows版本过低:
-> 要么升级win系统(不想);要么关掉Hyper-V去安装toolbox虚拟机,太复杂了。去知乎上搜索了一番后悟了:
遂放弃在windows上安装docker。
将本地代码上传到服务器(腾讯云上Orca Term提供了上传文件功能)
注意虚拟环境venv文件夹涉及到一个问题:docker容器本身就是一个虚拟环境了,不需要再在里面生成虚拟环境。
我是在解决别的问题时看见评论区得到的启发:
搜了一下别的资料:Activate python virtualenv in Dockerfile,佐证了这个观点,放弃采用虚拟环境(Dockerfile和boot.sh要做对应的修改,这俩文件的最终完整版在下面)
ps:假如仍然按照书上的做法用虚拟环境,也要注意:venv文件夹不能传过去,本地venv是windows环境下的虚拟环境,和linux不一样。根据linux系统的python版本,选择不同的指令生成虚拟环境(狗书的1.3和1.4章节有介绍),最后服务器的/home/flasky目录结构如下:
进入到/home/flasky目录,按照书上的命令运行docker build创建image,根据image 创建并运行容器。docker ps -a 查看容器运行状况,容器的STATUS不是预期的Up
,而是Exited (127)
,docker logs 指令查看报错信息:
/bin/sh: 1: flask: not found
/bin/sh: 2: exec: gunicorn: not found
为什么找不到命令?明明在Dockerfile中requirements.txt一个一个安装了这些包。搜了很多方法,也重新装了很多次,都失败。
最终发现在某一次Dockerfile重新生成image的过程中,很快闪过了几个WARNING
WARNING: The script gunicorn is installed in '/home/flasky/.local/bin' which is not on PATH.
Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
将这个环境变量写进Dockerfile中:ENV PATH=/home/flasky/.local/bin:$PATH
,再重新生成image就行了。参考资料:Default pip package PATH in python:3.8-slim-buster docker image
这个是让docker build过程的输出停留的方式:Why is docker build not showing any output from commands?这么重要的消息一闪而过很不友好,我重装了无数次才发现有这个WARNING…
再根据image生成容器,docker ps -a 查看状态,好歹是up起来了
docker logs myflasky111查看日志,又遇到了报错
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: posts
docker exec -it 容器id /bin/bash
进入容器内用flask db migrate + flask db upgrade
做一下数据迁移,再重启容器。查看logs,又报错
Target database is not up to date.
参考Target database is not up to date 用了三条指令可以解决(flask db stamp head + flask db migrate + flask db upgrade
)
但是在运行第三条指令flask db upgrade
时,没有权限访问最新的迁移文件
PermissionError: [Errno 13] Permission denied: '/home/flasky/migrations/versions/71f743fdbb14_.py'
想了很多办法给flasky用户加权限,什么添加用户组和用户,什么重置密码,最终以不知道root用户的密码告终(所以有谁知道腾讯云服务器root用户的密码是啥,我一进服务器就是root了不需要输入密码啊QAQ)
参考PermissionError: [Errno 13] Permission denied: ‘/manage.py’ 尝试使用
sudo chgrp -R docker /home/flasky/migrations/versions
和
sudo chmod -R g+rw /home/flasky/migrations/versions
(ps:如果没有docker组,就去创建:groupadd <用户组名称>
,将当前用户添加到指定组:usermod -a -G <用户组名称> <用户名称>
,如果报错没有权限: usermod: Permission denied.usermod: cannot lock /etc/passwd; try again later.
,用root身份进容器( docker exec -u 0 -it 容器id /bin/bash
),再执行usermod -a -G <用户组名称> <用户名称>
。命令参考)
它让我输入flasky用户的密码,可是我记得我在Dockerfile中只添加了flasky用户,没给它设置密码啊
查看资料怎么设置flasky用户的密码:How to add users to Docker container?在评论区看到,Dockerfile中加上RUN echo 'newuser:newpassword' | chpasswd
根据参考文章,重新编辑Dockerfile,完整文件如下:(如果不用编辑Dockerfile,遇到Permission denied报错后运行上面两行sudo命令,需要重启容器,权限才能生效,我这里重新编辑Dockerfile重新生成镜像容器,也相当于重启了。)
FROM python:3.7
ENV FLASK_APP flasky.py
ENV FLASK_CONFIG docker
RUN useradd -ms /bin/bash flasky
RUN echo 'flasky:你的密码' | chpasswd
RUN adduser flasky sudo
USER flasky
WORKDIR /home/flasky
ENV PATH=/home/flasky/.local/bin:$PATH
COPY requirements requirements
RUN /usr/local/bin/python -m pip install --upgrade pip
RUN pip install -r requirements/common.txt
COPY app app
COPY migrations migrations
COPY flasky.py config.py boot.sh ./
# run-time configuration
EXPOSE 5000
ENTRYPOINT ["./boot.sh"]
完整boot.sh文件如下
#!/bin/sh
flask deploy
exec gunicorn -b :5000 --access-logfile - --error-logfile - flasky:app
构建image,生成容器,进入容器运行flask db upgrade提示PermissionError: [Errno 13] Permission denied
时,执行sudo chgrp -R docker /home/flasky/migrations/versions
和 sudo chmod -R g+rw /home/flasky/migrations/versions
,输入上面在Dockerfile中设置的密码。(根据后来的经验,/home/flasky/app/static/avatars文件夹也会报权限错误,也对它运行一下这两个指令吧!)
exit命令退出容器,docker logs 容器id
查看日志,我的天,终于不报错了,泪目T^T
ps:
apt-get install vim
安装一下,报错:python List directory /var/lib/apt/lists/partial is missing. -Acquire (13: Permission denied)
需要 docker exec -u 0 -it 容器id /bin/bash
采用root身份进入容器内再安装
接下来研究怎样让我的web app 公开可访问
参考一些:资料0,资料1,资料2,资料3,资料4,资料5,资料6
在腾讯云控制台的防火墙开放对应端口
docker run 的时候指定了端口映射,docker ps -a 可以查看映射细节。
0.0.0.0:8000->5000的意思是,开放容器的5000端口,对接到linux服务器(宿主机)的8000端口
进入容器内访问app: curl localhost:5000,能返回正确地html
容器内也能联网
退出容器,在linux服务器上访问容器内的app,curl localhost:8000,也能正确地返回html
最后喊你的小伙伴来访问你的app吧!地址:去腾讯云控制台查看服务器的公网ip+8000端口
(ps:docker ps -f 容器名
查看日志,加上-f参数就可以动态显示实时刷新的log,按Ctrl C 退出)
最后附上一点参考资料:How To Deploy a Flask App on Docker Containers
Docker container build failed: /bin/sh: 1: flask: not found