本次作业为Python专题。Python是将练习使用docker容器运行Python程序。Python是很常用的程序设计语言,但是Python程序的运行依赖于提前的系统环境配置,为了降低系统配置的复杂度,同时减小资源开销,将系统环境容器化是一种解决方案。请根据Python官方镜像的镜像说明,自定义Python镜像文件,将Python程序运行起来。

1.项目结构

首先我们先建立好文件结构,便于后续实验

2.搭建python镜像

Dockerfile

FROM python:3
MAINTAINER qaq
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install  --default-timeout=100 --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
VOLUME /usr/src/app
ENTRYPOINT [ "python" ]  # 实现命令行式调用容器
CMD ["python"]

requirements.txt

PyMySQL
opencv-python

搭建镜像

这里需要在root下运行

docker build -t docker:py .

创建一个网络,接下来的Mysql和Python容器均要运行在同一个网络中才能相互访问。

docker network create --subnet=172.1.0.0/16 py_mysql

3、简单程序的部署运行

helloworld

#hello.py
print('hello world!')
print('hello world!!')
print('hello world!!!')

sudo docker run --rm -v /home/qinhonghao/dockpy/app:/usr/src/app docker:py hello.py

日历输出

#date.py
import calendar
year = int(input("输入年份: "))
month = int(input("输入月份: "))
print(calendar.month(year,month))

sudo docker run -it --rm -v /home/qinhonghao/dockpy/app:/usr/src/app docker:py date.py

mysql数据库操作

先开启一个数据库容器,可以用之前搭建好的(例如上次试验创建的mysql容器)
docker start 容器id

测试数据库连接

#ms1.py
#!/usr/bin/python3
 
import pymysql
 
# 打开数据库连接
db = pymysql.connect(host="mysql",user="root",password="123456",database="docker_mysql" )

# 使用 cursor() 方法创建一个游标对象 cursor
cursor = db.cursor()
 
# 使用 execute()  方法执行 SQL 查询 
cursor.execute("SELECT VERSION()")
 
# 使用 fetchone() 方法获取单条数据.
data = cursor.fetchone()
 
print ("Database version : %s " % data)
 
# 关闭数据库连接
db.close()

sudo docker run -it --rm -v /home/qinhonghao/dockpy/app:/usr/src/app --link=mysql --net compose4_webnet docker:py ms1.py

这样就代表数据库连接成功了!!!

创建表和插入数据

#ms2.py
#!/usr/bin/python3
 
import pymysql
 
# 打开数据库连接
db = pymysql.connect(host="mysql",user="root",password="123456",database="docker_mysql" )
 
# 使用 cursor() 方法创建一个游标对象 cursor
cursor = db.cursor()
 
# 使用 execute() 方法执行 SQL,如果表存在则删除
cursor.execute("DROP TABLE IF EXISTS STUDENT")
 
# 使用预处理语句创建表
sql = """CREATE TABLE STUDENT (
         SNO CHAR(20) NOT NULL,
         SNAME  CHAR(20),
         AGE INT,  
         SEX CHAR(1),
         SDEPT CHAR(20),
         GRADE INT )"""
 
cursor.execute(sql)

# SQL 插入语句
sql1 = """INSERT INTO STUDENT(SNO, SNAME,
         AGE, SEX, SDEPT, GRADE)
         VALUES ('20200437', 'YMT', 20, 'F', 'NEWS', 98)"""
try:
   # 执行sql语句
   cursor.execute(sql1)
   # 提交到数据库执行
   db.commit()
except:
   # 如果发生错误则回滚
   db.rollback()

# SQL 插入语句
sql2 = """INSERT INTO STUDENT(SNO, SNAME,
         AGE, SEX, SDEPT, GRADE)
         VALUES ('20200101', 'QHH', 20, 'M', 'CS', 99)"""
try:
   # 执行sql语句
   cursor.execute(sql2)
   # 提交到数据库执行
   db.commit()
except:
   # 如果发生错误则回滚
   db.rollback()
 
# 关闭数据库连接
db.close()

这里不知道为什么会出现warning,但是不影响表的创建和数据的插入。

查询表中某条数据

#ms3.py
#!/usr/bin/python3
 
import pymysql
 
# 打开数据库连接
db = pymysql.connect(host="mysql",user="root",password="123456",database="docker_mysql" )
 
# 使用cursor()方法获取操作游标 
cursor = db.cursor()
 
# SQL 查询语句
sql = "SELECT * FROM STUDENT \
       WHERE GRADE > %s" % (98)
try:
   # 执行SQL语句
   cursor.execute(sql)
   # 获取所有记录列表
   results = cursor.fetchall()
   for row in results:
      sno = row[0]
      sname = row[1]
      age = row[2]
      sex = row[3]
      sdept = row[4]
      grade = row[5]
       # 打印结果
      print ("sno=%s,sname=%s,age=%s,sex=%s,sdept=%s,grade=%s" % \
             (sno, sname, age, sex, sdept, grade ))
except:
   print ("Error: unable to fetch data")
 
# 关闭数据库连接
db.close()


可以看到,我想查询的数据已经得到了。

修改数据库中STUDENT表的数据

#ms4.py
#!/usr/bin/python3
 
import pymysql
 
# 打开数据库连接
db = pymysql.connect(host="mysql",user="root",password="123456",database="docker_mysql" )

# 使用cursor()方法获取操作游标 
cursor = db.cursor()
 
# SQL 更新语句
sql1 = "UPDATE STUDENT SET AGE = AGE + 1 WHERE SEX = '%c'" % ('M')
try:
   # 执行SQL语句
   cursor.execute(sql1)
   # 提交到数据库执行
   db.commit()
except:
   # 发生错误时回滚
   db.rollback()

# SQL 更新语句
sql2 = "UPDATE STUDENT SET GRADE = 100 WHERE SNAME = '%s'" % ('YMT')
try:
   # 执行SQL语句
   cursor.execute(sql2)
   # 提交到数据库执行
   db.commit()
except:
   # 发生错误时回滚
   db.rollback()
 
# 关闭数据库连接
db.close()

数据库中STUDENT表数据的更新已经成功。

opencv程序

函数 cv2.moments() 会将计算得到的矩以一个字典的形式返回

#cvv.py
import cv2
import numpy as np

img = cv2.imread('test.jpg',0)
ret,thresh = cv2.threshold(img,127,255,0)
contours,hierarchy = cv2.findContours(thresh, 1, 2)

cnt = contours[0]
M = cv2.moments(cnt)
print (M)

sudo docker run --rm -v /home/qinhonghao/dockpy/app:/usr/src/app docker:py cvv.py

4、遇到的问题和解决方法

1、运行hello.py失败


解决办法:我把Dockerfile里面的工作目录WORKDIR换成/usr/src/app,重启docker就好了

2、日历运行错误


解决办法:这里错误的原因是我把运行hello.py的命令复制粘贴了过来只改了文件名,所以我在docker run 后面加上-it,表示声明需要交互式终端,然后才正确运行了,可以输入。

3、数据库连接错误1


解决办法:我百度后发现原因是,Docker 在启动一个容器时,会为其创建一个默认网络-containerName_defaul,所以使用--link方式互联容器时由于默认不在一个网络中,会报上述错误,解决办法:docker inspect [需要link的容器名称或ID],查看要link的容器的网络名称,例如下图的红框中标注的bridge,然后添加--net 容器名称,使新的container与link目标在同一个网络中。比如我的就改成这样
sudo docker run -it --rm -v /home/qinhonghao/dockpy/app:/usr/src/app --link=mysql --net compose4_webnet docker:py ms1.py

4、数据库连接错误2


解决办法:这里的错误在于docker_mysql数据库还没创建,所以create database docker_mysql创建就可以了

5、时间花费

(1)搭建镜像:大约20min
(2)程序部署:大约4h
(3)编写博客:大约1h10min
总计:大约5.5h

6、感想总结

这次作业总体量不多,难度也不大,但是总是会出现各种莫名其妙的意外错误,总之不论如何,要学会自己单独寻找方法、解决问题。