Docker入门学习教程

Docker入门学习

文章目录

  • Docker入门学习
  • 1.简介
  • 2 基本概念
    • 2.1 镜像(Image)
    • 2.2 容器(Container)
    • 2.3 仓库(Repository)
  • 3.Windows Docker安装
    • 3.1 更改默认安装位置
    • 3.2 安装步骤
  • 4.使用镜像
    • 4.1 获取镜像
    • 4.2 列出镜像
    • 4.3 删除本地镜像
  • 5.容器
    • 5.1 启动容器
      • 5.1.1 新建并启动
      • 5.1.2 启动已终止容器
    • 5.2 后台运行
    • 5.3 终止容器
    • 5.4 进入容器
      • 5.4.1 attach命令
      • 5.4.2 exec 命令
    • 5.5 删除容器
  • 6.定制镜像
  • 7.目录挂载
    • 7.1 数据卷(Volumes)
    • 7.2 挂载主机目录
  • 8.Docker Compose
      • 问题1:Flask容器不能访问MySQL容器,多次更改主机号都连接不上。
      • 问题2:RuntimeError: ‘cryptography’ package is required for sha256_password or caching_sha2_password auth methods
  • 9.发布和部署
  • 实践1.Docker安装MySQL
      • 问题:sqlyog:2058连接错误

1.简介

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows操作系统的机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。

简单来说,Docker可以简化开发环境配置;方便不同系统(Windows/Mac/Linux),不同环境(生产环境,预发环境和开发环境)的程序部署迁移。

Docker 和传统虚拟化方式的区别:

  • 传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;
  • 容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。

2 基本概念

2.1 镜像(Image)

Docker 镜像 是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

可以理解为软件安装包,可以方便的进行传播和安装。

2.2 容器(Container)

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

容器的实质是进程。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。

可以理解为软件安装后的状态,每个软件运行环境都是独立的、隔离的,称之为容器。

2.3 仓库(Repository)

镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry就是这样的服务。

一个Docker Registry中可以包含多个仓库Repository);每个仓库可以包含多个标签Tag);每个标签对应一个镜像。

通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。

仓库名经常以两段式路径形式出现,比如 kint216/flask,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务。

3.Windows Docker安装

3.1 更改默认安装位置

因为Docker的默认安装位置在C盘,而我的C盘容量越来越小,故采取了以下的方式更改Docker的安装位置。

# Docker的安装位置:
# C:\Program Files\Docker
# C:\ProgramData\Docker
# C:\ProgramData\DockerDesktop
# C:\Users\你的用户名\AppData\Local\Docker
# C:\Users\你的用户名\AppData\Roaming\Docker

在有管理员权限的cmd中执行以下命令:

mklink /j "C:\Program Files\Docker" "自定义的位置"

在这里插入图片描述

"自定义的位置“必须在执行命令前手动建立。执行完上面的命令后直接安装docker就行了。该命令会在“默认的位置”那创建一个指向“自定义位置”的快捷方式(和自己添加的快捷方式不同)。如果想撤回这个命令的话,在”默认的位置“那把快捷方式删了就行。

3.2 安装步骤

下载地址:https://hub.docker.com/editions/community/docker-ce-desktop-windows

  • 双击下载好的exe文件,配置勾选下面两个选择,自动安装相应的配置。

Docker入门学习教程_第1张图片

  • 配置下载完成后需要重启电脑。

  • 启动Docker时报错,需要手动更新WSL 2内核。

Docker入门学习教程_第2张图片

  • 根据提示的连接中的步骤4下载 Linux 内核更新包,下载后手动更新。

Docker入门学习教程_第3张图片

  • 此时可以正常打开Docker,显示页面如下。
    Docker入门学习教程_第4张图片

  • 设置镜像源,加快下载速度。

镜像加速器 镜像加速器地址
Docker 中国官方镜像 https://registry.docker-cn.com
DaoCloud 镜像站 http://f1361db2.m.daocloud.io
Azure 中国镜像 https://dockerhub.azk8s.cn
科大镜像站 https://docker.mirrors.ustc.edu.cn
阿里云 https://.mirror.aliyuncs.com
七牛云 https://reg-mirror.qiniu.com
网易云 https://hub-mirror.c.163.com
腾讯云 https://mirror.ccs.tencentyun.com

Docker入门学习教程_第5张图片

# 加入的代码如下
  "registry-mirrors": [
    "https://registry.docker-cn.com",
    "https://docker.mirrors.ustc.edu.cn",
    "https://mirror.ccs.tencentyun.com"
  ],

4.使用镜像

4.1 获取镜像

Docker Hub 上有大量的高质量的镜像可以用,从 Docker镜像仓库获取镜像的命令是docker pull。其命令格式为:

$ docker pull [选项] [Docker Registry地址[:端口号]/]仓库名[:标签]

具体的选项可以通过 docker pull --help 命令看到,这里我们说一下镜像名称的格式。

  • Docker 镜像仓库地址:地址的格式一般是 <域名/IP>[:端口号]。默认地址是 Docker Hub(docker.io)。
  • 仓库名:这里的仓库名是两段式名称,即 <用户名>/<软件名>。对于 Docker Hub,如果不给出用户名,则默认为 library,也就是官方镜像。
$ docker pull ubuntu:18.04
18.04: Pulling from library/ubuntu
284055322776: Pull complete
Digest: sha256:0fedbd5bd9fb72089c7bbca476949e10593cebed9b1fb9edf5b79dbbacddd7d6
Status: Downloaded newer image for ubuntu:18.04
docker.io/library/ubuntu:18.04

上面的命令中没有给出 Docker 镜像仓库地址,因此将会从 Docker Hub (docker.io)获取镜像。而镜像名称是 ubuntu:18.04,因此将会获取官方镜像 library/ubuntu 仓库中标签为 18.04 的镜像。docker pull 命令的输出结果最后一行给出了镜像的完整名称,即: docker.io/library/ubuntu:18.04

4.2 列出镜像

列出已经下载的镜像,可以使用 docker image ls 命令。

$ docker image ls
REPOSITORY                                                 TAG       IMAGE ID       CREATED        SIZE
docker/getting-started                                     latest    26d80cd96d69   2 months ago   28.5MB
ubuntu                                                     18.04     5a214d77f5d7   4 months ago   63.1MB
ubuntu                                                     bionic    5a214d77f5d7   4 months ago   63.1MB
ccr.ccs.tencentyun.com/dockerpracticesig/docker_practice   latest    a54473bbb25a   7 months ago   47.3MB

列表包含了 仓库名标签镜像 ID创建时间 以及 所占用的空间

镜像 ID则是镜像的唯一标识,一个镜像可以对应多个标签。因此,在上面的例子中,我们可以看到 ubuntu:18.04ubuntu:bionic 拥有相同的 ID,因为它们对应的是同一个镜像。

不加任何参数的情况下,docker image ls 会列出所有顶层镜像,但是有时候我们只希望列出部分镜像。docker image ls 有好几个参数可以帮助做到这个事情。

  • 根据仓库名列出镜像
$ docker image ls ubuntu
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
ubuntu       18.04     5a214d77f5d7   4 months ago   63.1MB
ubuntu       bionic    5a214d77f5d7   4 months ago   63.1MB
  • 列出特定的某个镜像,也就是说指定仓库名和标签
$ docker image ls ubuntu:18.04
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
ubuntu       18.04     5a214d77f5d7   4 months ago   63.1MB

$ docker image ls ubuntu:bionic
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
ubuntu       bionic    5a214d77f5d7   4 months ago   63.1MB

4.3 删除本地镜像

删除本地的镜像,可以使用 docker image rm 命令,其格式为:

$ docker image rm [选项] <镜像1> [<镜像2> ...]

其中,<镜像> 可以是 镜像短 ID镜像长 ID镜像名

比如我们有这么一些镜像:

$ docker image ls
REPOSITORY                                                 TAG       IMAGE ID       CREATED        SIZE
docker/getting-started                                     latest    26d80cd96d69   2 months ago   28.5MB
ubuntu                                                     18.04     5a214d77f5d7   4 months ago   63.1MB
ubuntu                                                     bionic    5a214d77f5d7   4 months ago   63.1MB
ccr.ccs.tencentyun.com/dockerpracticesig/docker_practice   latest    a54473bbb25a   7 months ago   47.3MB

我们可以用镜像的完整 ID,也称为 长 ID,来删除镜像,但更多的时候是用 短 ID 来删除镜像。docker image ls 默认列出的就已经是短 ID 了,一般取前3个字符以上,只要足够区分于别的镜像就可以了。

比如这里,如果我们要删除 docker/getting-started 镜像,可以执行:

$ docker image rm 26d
Untagged: docker/getting-started:latest
Untagged: docker/getting-started@sha256:86093b75a06bf74e3d2125edb77689c8eecf8ed0cb3946573a24a6f71e88cf80
Deleted: sha256:26d80cd96d6905cdc4f95c8e4cac9e1dce43cc9d81054fff28371728435891a8
Deleted: sha256:417302e3ee3f952e11b2c25c5295ac437e9eceb97b5d50683ab9717688c2c47a
Deleted: sha256:8dfa110a9ba2693c02cc4311773b7a7ebdd02a8be91d089cd4cfc4a7ca51a75c
Deleted: sha256:57dba6dab88290f4e9b3125f9e6b3b088626af1fe3a93d47056c030ac7d51c1c
Deleted: sha256:67c225b96afdfdb9c2b8f6f7284d771fe20ff5ebabc65a088afeca1fbafadbee
Deleted: sha256:d8242f1082c90da0b3819a2737bc23215237e2440857a0c5ec0904abc81e81b0
Deleted: sha256:329df243003cb0259caf109da224f24391d0a4e3fe419fde5a6f092ee27424fe
Deleted: sha256:bdb2ce57de00bca016d44a1def44f2a281dfe027bbc4975d65c8ff4cf04d63fb
Deleted: sha256:1a058d5342cc722ad5439cacae4b2b4eedde51d8fe8800fcf28444302355c16d

我们也可以用镜像名,也就是 <仓库名>:<标签>,来删除镜像。

$ docker image rm ubuntu:18.04
Untagged: ubuntu:18.04

如果观察上面这几个命令的运行输出信息的话,你会注意到删除行为分为两类,一类是 Untagged,另一类是 Deleted。我们之前介绍过,镜像的唯一标识是其 ID 和摘要,而一个镜像可以有多个标签。

因此当我们使用上面命令删除镜像的时候,实际上是在要求删除某个标签的镜像,这就是 Untagged 的信息。因为一个镜像可以对应多个标签,因此当我们删除了所指定的标签后,可能还有别的标签指向了这个镜像,如果是这种情况,那么 Delete 行为就不会发生。所以在执行docker image rm ubuntu:18.04指令时,只是仅取消了标签名18.04,因为该ubuntu镜像还有其他的标签名bionic

当该镜像所有的标签都被取消了,该镜像很可能会失去了存在的意义,因此会触发删除行为。镜像是多层存储结构,因此在删除的时候也是从上层向基础层方向依次进行判断删除。镜像的多层结构让镜像复用变得非常容易,因此很有可能某个其它镜像正依赖于当前镜像的某一层。这种情况,依旧不会触发删除该层的行为。直到没有任何层依赖当前层时,才会真实的删除当前层。

除了镜像依赖以外,还需要注意的是容器对镜像的依赖。如果有用这个镜像启动的容器存在(即使容器没有运行),那么同样不可以删除这个镜像。如果这些容器是不需要的,应该先将它们删除,然后再来删除镜像。

5.容器

容器是独立运行的一个或一组应用,以及它们的运行态环境。

5.1 启动容器

启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(exited)的容器重新启动。

5.1.1 新建并启动

有了镜像后,我们就能够以这个镜像为基础启动并运行一个容器。使用的命令主要为 docker run

例如,下面的命令则启动一个 bash 终端,允许用户进行交互。

$ docker run -it --rm ubuntu:18.04 bash

root@10781f4737ca:/# cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.6 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.6 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
root@10781f4737ca:/# exit
exit
  • -it:这是两个参数,一个是 -i交互式操作,一个是 -t 终端,即交互式终端。
  • --rm:这个参数是说容器退出后随之将其删除。
  • ubuntu:18.04:这是指用 ubuntu:18.04 镜像为基础来启动容器。
  • bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 bash

进入容器后,我们可以在 Shell 下操作,执行任何所需的命令。这里,我们执行了 cat /etc/os-release,这是 Linux 常用的查看当前系统版本的命令,从返回的结果可以看到容器内是 Ubuntu 18.04.1 LTS 系统。最后我们通过 exit 退出了这个容器。

当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:

  • 检查本地是否存在指定的镜像,不存在就从registry下载
  • 利用镜像创建并启动一个容器
  • 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
  • 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去(-p参数)
  • 从地址池配置一个 ip 地址给容器
  • 执行用户指定的应用程序
  • 执行完毕后容器被终止

5.1.2 启动已终止容器

可以利用 docker container start 命令,直接将一个已经终止(exited)的容器启动运行。

5.2 后台运行

更多的时候,需要让 Docker 在后台运行而不是直接把执行命令的结果输出。此时,可以通过添加 -d 参数来实现。

如果不使用 -d 参数运行容器。

$ docker run ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
hello world
hello world
hello world
hello world

从上面的例子中可以看到,容器会把输出的结果打印出来。

如果使用了 -d 参数运行容器。

$ docker run -d ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
9822df018d4e99c8057af442a90f5b18dd4e73ea40627602bba4312f38364300

此时容器会在后台运行并不会把输出的结果打印(输出结果可以用 docker logs 查看)。

使用 -d 参数启动后会返回一个唯一的 id,也可以通过 docker container ls 命令来查看容器信息。

要获取容器的输出信息,可以通过 docker container logs 命令。

$ docker container logs [container ID or NAMES]
hello world
hello world
hello world
. . .

在docker desktop中也可以查看容器的logs。

Docker入门学习教程_第6张图片

5.3 终止容器

可以使用 docker container stop 来终止一个运行中的容器。此外,当 Docker 容器中指定的应用终结时,容器也自动终止。

$ docker container stop [container ID]

处于终止状态的容器,可以通过 docker container start 命令来重新启动。

此外,docker container restart 命令会将一个运行态的容器终止,然后再重新启动它。

5.4 进入容器

在使用 -d 参数时,容器启动后会进入后台。某些时候需要进入容器进行操作,可以使用 docker attach 命令或 docker exec 命令。

5.4.1 attach命令

# 启动容器
$ docker run -dit ubuntu
862613a2556eb1dcd3aefcd954ee0eda25ee71d21baba0f6ed4fb364b05cd680

# 查看容器状态
$ docker container ls
CONTAINER ID   IMAGE     COMMAND   CREATED         STATUS         PORTS     NAMES
862613a2556e   ubuntu    "bash"    3 seconds ago   Up 2 seconds             infallible_cori

# 根据container ID进入某一容器
$ docker attach 862
# 退出
root@862613a2556e:/# exit
exit

# 查看结束attach指令后的容器状态
$ docker container ls
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

如果exit,会导致容器的停止。

5.4.2 exec 命令

# 启动容器
$ docker run -dit ubuntu
6f242cd3ca38dbc32e85d55821ed23336a2b935fa19a8aa97d42df054723477d

# 查看容器状态
$ docker container ls
CONTAINER ID   IMAGE     COMMAND   CREATED         STATUS         PORTS     NAMES
6f242cd3ca38   ubuntu    "bash"    4 seconds ago   Up 3 seconds             naughty_williamson

# 根据container ID进入某一容器
$ docker exec -it 6f24 bash
# 查看当前目录
root@6f242cd3ca38:/# ls
bin  boot  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
# 退出
root@6f242cd3ca38:/# exit
exit

# 查看结束exec指令后的容器状态
$ docker container ls
CONTAINER ID   IMAGE     COMMAND   CREATED         STATUS         PORTS     NAMES
6f242cd3ca38   ubuntu    "bash"    5 minutes ago   Up 5 minutes             naughty_williamson

如果exit,不会导致容器的停止。

推荐使用 docker exec 指令。

5.5 删除容器

可以使用docker container rm 来删除一个处于终止状态的容器。

$ docker container rm [container ID]

如果要删除一个运行中的容器,可以添加 -f 参数。Docker 会发送 SIGKILL 信号给容器。

docker container ls -a 命令可以查看所有已经创建的包括终止状态的容器,如果数量太多要一个个删除可能会很麻烦,用下面的命令可以清理掉所有处于终止状态的容器。

$ docker container prune

6.定制镜像

镜像是容器的基础,每次执行 docker run 的时候都会指定哪个镜像作为容器运行的基础。在之前的例子中,我们所使用的都是来自于 Docker Hub 的镜像。直接使用这些镜像是可以满足一定的需求,而当这些镜像无法直接满足需求时,我们就需要定制这些镜像。

下面通过基于Flask框架的一个demo做演示。

文件目录结构

demo/
    app.py
    requirements.txt
    Dockerfile

后端代码如下,打开网页显示Hello, World!

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    return "Hello, World!"

if __name__ == '__main__':
   app.run(host='0.0.0.0')

requirements.txt内容如下:

flask

Dockerfile内容如下:

# FROM 指定基础镜像
FROM python:3.8-slim-buster
# 指定Docker命令的工作路径,如果路径不存在,Docker会自动创建
WORKDIR /app
# 将所有程序拷贝到Docker镜像中
# COPY <本地路径> <目标路径>
# 第一个'.'代表程序根目录下的所有文件;第二个'.'代表Docker镜像中的路径,即当前的工作路径'/app/'
COPY . .
# 创建镜像,安装环境,RUN指令是在创建镜像时使用
RUN pip install -r requirements.txt
# CMD指令用来指定当Docker容器运行起来执行的命令
CMD ["python","app.py"]

Dockerfile文件目录下输入指令,-t参数是指定镜像名称,.告诉docker在该目录下寻找Dockerfile文件

$ docker build -t demo .

docker按照我们编写的指令逐步执行,如下图。

Docker入门学习教程_第7张图片

然后我们通过docker run指令来启动一个容器。-p是将容器上的某一个端口映射到本地主机上,这样我们才能从主机上访问容器中的Web服务,前面的8080是本地主机上的端口,后面的5000是容器上的端口;-d让容器在后台运行,这样输出不会直接显示在控制台;--name参数指定容器的名称,如果未设置Docker会随机生成一个容器名称。

$ docker run -p 8080:5000 -d --name web demo

此时在浏览器打开localhost:8080,就可以在网页中看到Hello World!

注意:Flask后端的代码主机号要写成0.0.0.0,否则容器启动后在本机上打开报错。

7.目录挂载

7.1 数据卷(Volumes)

数据卷是一个可供一个或多个容器使用的特殊目录,有以下特性:

  • 可以在容器之间共享和重用
  • 对数据卷的修改会立马生效
  • 更新数据卷不会影响镜像
  • 数据卷默认会一直存在,即使容器被删除
# 创建一个数据卷
$ docker volume create 数据卷名字

# 查看所有的数据卷
$ docker volume ls

# 在主机里使用以下命令可以查看指定数据卷的信息
$ docker volume inspect 数据卷名字

# 删除数据卷
$ docker volume rm my-vol

# 删除不使用的数据卷
$ docker volume prune

下面演示启动一个挂载数据卷的容器:

# 创建数据卷
$ docker volume create test
test

# 查看数据卷
$ docker volume ls
DRIVER    VOLUME NAME
local     test

# 用ubuntu镜像创建一个名为test的容器,且将新创建的数据卷挂载到/volume目录下,如果没有该目录Docker会自动创建
$ docker run -dit --name test -v test:/volume ubuntu
57cc84da548f5f60da942e77cd5bf3ec9be5baff31adb3dfa21178bf1a5587cc

# 进入容器,创建测试文件
$ docker exec -it 57cc bash
root@57cc84da548f:/# cd volume
root@57cc84da548f:/volume# touch test.txt

此时可以看到数据卷中也出现了测试文件。

Docker入门学习教程_第8张图片

7.2 挂载主机目录

在本地创建一个挂载目录,这里我用的目录是D:\Volume

挂载一个本地主机目录作为数据卷,命令如下:

# 用ubuntu镜像创建一个名为test的容器,且将本地目录挂载到/volume目录下,如果没有该目录Docker会自动创建
$ docker run -dit --name test01 -v /d/Volume:/volume ubuntu

为了能够在容器中修改文件,我在容器里安装vim,用到指令如下:

# 更新apt源
apt-get update 
# 安装vim
apt-get install -y vim

在容器中创建文件:

$ docker exec -it test01 bash
root@7c6623ff53d2:/# cd volume
# 创建测试文件,内容为“Container test”
root@7c6623ff53d2:/volume# vim test.txt

本地文件夹中也会同步更新。

Docker入门学习教程_第9张图片

8.Docker Compose

在很多情况下,我们需要多个容器相互配合来完成某项任务。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。Compose 恰好满足了这样的需求。它允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。

这里我使用一个简单的个人博客系统作为演示,包括Flask后端和MySQL数据库两部分。
仓库地址:https://github.com/LenkyAndrews/notebook-docker

文件目录如下:

notebook/
    docker-compose.yml
    flask/
    	...
    	dockerfile
    mysql/
    	notebook.sql
    	dockerfile

后端flask文件夹中的dockerfile如下:

FROM python:3.8-slim-buster
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt -i  https://mirrors.aliyun.com/pypi/simple/
CMD ["python","app.py"]

数据库mysql文件夹中的dockerfile如下:

FROM mysql
COPY ./notebook.sql /docker-entrypoint-initdb.d

notebook.sql是数据库初始化文件,它会把flask应用需要用到的库和表创建出来。在mysql官方镜像中提供了容器启动时自动执行/docker-entrypoint-initdb.d文件夹下的脚本的功能(包括shell脚本和sql脚本) 。因此我们只要把初始化文件在镜像启动时复制到/docker-entrypoint-initdb.d文件夹就可以了。

要把项目依赖的多个服务集合到一起,我们需要编写一个docker-compose.yml文件,描述依赖哪些服务。

# 版本号
version: '3'

services:
  # 定义数据库容器
  mysql:
  	# 执行数据库文件夹下的dockerfile
    build: ./mysql
    # 设置主机和容器的端口映射
    ports:
      - "3307:3306"
    environment:
    # 设置root用户密码
      - MYSQL_ROOT_PASSWORD=123456
  # 定义后端容器
  flask:
  	# 执行后端文件夹下的dockerfile
    build: ./flask
    # 设置主机和容器的端口映射
    ports:
      - "5000:5000"

完成以上步骤后,在docker-compose.yml 文件所在目录,执行命令:

$ docker-compose up -d

问题1:Flask容器不能访问MySQL容器,多次更改主机号都连接不上。

# 后端报错提示
pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on '0.0.0.0' ([Errno 111] Connection refused)")

网页报错提示如下:

在这里插入图片描述

解决方案:
githubstack overflow上查询类似的问题后,发现是我的host和port写错了。host应该写成数据库服务的名称,即docker-compose.yml中的mysql;因为我将容器的端口3306映射到本地主机的端口3307,之前我一直写的是3307端口没成功,这两个容器是处在同一个网络中的,所以改成3306端口后就可以相互通信了。

# 数据库连接代码
class MysqlUtil():
    def __init__(self):
        host = 'mysql'  # 主机名
        port = 3306  # 端口号
        user = 'root'  # 数据库用户名
        password = '123456'  # 数据库密码
        database = 'notebook'  # 数据库名称
        self.db = pymysql.connect(host=host, port=port, user=user, password=password, db=database)  # 建立连接
        self.cursor = self.db.cursor(cursor=pymysql.cursors.DictCursor)  # 设置游标,并将游标设置为字典类型

问题2:RuntimeError: ‘cryptography’ package is required for sha256_password or caching_sha2_password auth methods

解决方法:
安装cryptography包,或者设置加密方式(在docker-compose.yml或手动修改)。

9.发布和部署

  1. 在Docker Hub上注册账号

  2. 创建一个镜像库

Docker入门学习教程_第10张图片

  1. 命令行登录账号:
$ docker login -u username
  1. 新建一个tag,名字跟注册账号一样
$ docker tag notebook_flask:latest username/notebook:v1

Docker入门学习教程_第11张图片

  1. 推到远端仓库
$ docker push username/notebook:v1

Docker入门学习教程_第12张图片

  1. 此时可以从远端仓库拉取部署使用
$ docker run -dp 8080:5000 --name hub_notebook username/notebook:v1

实践1.Docker安装MySQL

# 拉取镜像
$ docker pull mysql

# 运行一个MySQL容器
# -p 3306:3306 :映射容器服务的3306端口到宿主机的3307端口,外部主机可以直接通过宿主机ip:3307访问到MySQL的服务。
# MYSQL_ROOT_PASSWORD=123456:设置MySQL服务root用户的密码。
$ docker run -itd --name mysql-test -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql

问题:sqlyog:2058连接错误

在本地主机连接mysql出现sqlyog:2058的错误。意思是客户端不支持caching_sha2_password的加密方式。

Docker入门学习教程_第13张图片

解决步骤:

  1. 进入容器
$ docker exec -it mysql-test bash
  1. 登录
mysql -uroot -p
  1. 查看一下当前root用户的加密方式,发现此时root用户的加密方式是caching_sha2_password
select user,host,plugin from mysql.user where user = 'root';

Docker入门学习教程_第14张图片

  1. 更改加密规则,需要重新设置root密码
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root密码'; 
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root密码';
  1. 刷新权限配置
flush privileges;

你可能感兴趣的:(Docker,docker,学习,容器,flask,mysql)