gogoend / blog

blogs, ideas, etc.
MIT License
9 stars 2 forks source link

Docker 简易快速入门笔记 #72

Open gogoend opened 2 years ago

gogoend commented 2 years ago

背景

突然看到电脑上安装的Docker,一直以来都只是装上了却没有用过,遂启动了提供的docker/getting-started项目,按照这个项目中的教程看了看。 —— 因此本文内容均来自官方教程,主要是对相关内容进行了提炼。

拉镜像

docker run -d -p 80:80 docker/getting-started

执行命令后,将会拉下来一个Docker镜像,并实例化一个容器。这里将容器的80端口暴露给了主机80的端口,通过主机访问 http://localhost 即可进入这个教程页面。

创建自己的镜像

打开教程提供的前端项目,在前端项目工作目录根文件夹创建一个名为Dockerfile的文件

FROM node:12-alpine
RUN apk add --no-cache python g++ make
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]

然后执行

docker build -t getting-started .

这里相当于以node:12-alpine镜像作为基础,创建一个包含node以及alpine的容器,同时会在容器中安装pythong++make;接下来似乎会在容器中的根目录下创建一个app根目录并切换到这个文件夹,如何会把主机上当前工作目录中的内容拷贝到其中,之后的步骤将会为工作目录中的前端项目安装依赖,并启动项目 —— 这里步骤和正常的前端项目一致,区别在于这一步是发生在容器当中的。

执行结束后,将会以当前容器为基础,创建好一个镜像。

启动容器

上一步的镜像创建好以后,执行

docker run -dp 3000:3000 getting-started

即可创建并启动一个容器。同样这里把容器的3000端口暴露到了主机的3000端口,通过主机访问 http://localhost:3000 即可进入一个todo示例应用的页面 —— 这里就相当于已经把应用给部署好了。

升级应用

当应用程序的源代码发生变化后,自然需要来更新一下容器中正在运行的项目。此时若执行

docker build -t getting-started .
docker run -dp 3000:3000 getting-started

将会导致报错 —— 因为上一步中创建的容器仍然在运行。这时我们需要停止、删除旧容器,然后才能为升级后的应用创建新容器,以替代旧应用。

可通过

docker ps

获得所有人容器列表,找到旧容器,借助

docker stop <the-container-id>

来停止旧容器,通过

docker rm <the-container-id>

再删除旧容器。

再执行

docker run -dp 3000:3000 getting-started

来启动新应用。

保持旧应用中的数据以在新应用中使用

旧应用的容器删除后,其中的数据也将一并删除。那是否有办法保持数据呢?Docker提供了存储卷(Volume)来解决这个问题。存储卷独立于容器而存在,且可以被多个容器共享使用。存储卷可被挂载到容器的文件夹中。

通过

docker volume create todo-db

即创建了一个名为todo-db的存储卷。

可通过

docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started

来将todo-db存储卷挂在到容器内/etc/todos文件夹下。当对/etc/todos中的内容进行操作时,即在操作todo-db存储卷中的内容。

在容器中开发项目

将主机中的真实目录挂载到容器中,并在容器中进行开发。

执行

docker run -dp 3000:3000 \
    -w /app -v "$(pwd):/app" \
    getting-started \
    sh -c "yarn install && yarn run dev"

这里同样将3000端口暴露到了主机的3000端口,将主机的$(pwd):/app挂载到容器中的/app目录下,并和日常开发一样执行yarn install && yarn run dev即可进入应用的开发模式。

可以通过

docker logs -f <container-id>

来查看控制台输出。

多容器交互

上面示例我们只用到了一个单独的容器。有时我们的应用想要跑起来,可能会依赖多个模块,而这些模块又分别由不同容器提供。例如后端服务由Node.js提供,数据库由MySQL提供。在Docker下,每个容器之间是隔离的。若要让容器与容器之间产生联系,可以将这些容器接入同一网络,以实现互相访问。

要创建网络,可以执行

docker network create todo-app

这就创建了一个名为todo-app的网络。 接下来我们可以基于MySQL镜像创建一个容器,同时让这个容器接入todo-app网络

docker run -d \
    --network todo-app \
    --network-alias mysql \
    -v todo-mysql-data:/var/lib/mysql \
    -e MYSQL_ROOT_PASSWORD=secret \
    -e MYSQL_DATABASE=todos \
    -p 3306:3306 \
    ibex/debian-mysql-server-5.7

这一步基于MySQL镜像创建了一个容器,同时也指定了MySQL的数据是存入todo-mysql-data存储卷里的 —— 虽然这里没有显式指明要创建一个存储卷,但Docker帮我们创建了;这里使用环境变量指定了数据库的一些信息;接下来指定了暴露给主机的端口。

MySQL官方镜像是mysql:5.7,不过笔者使用的是基于ARM的处理器,官方镜像不支持基于ARM的处理器,因此使用了其他开发者贡献的支持基于ARM处理器的镜像ibex/debian-mysql-server-5.7

MySQL容器创建后,可以通过

docker exec -it <mysql-container-id> mysql -p

执行语句

SHOW DATABASES;

检查数据库是否创建成功

下面就可以把我们的应用与MySQL进行连接了。

执行

docker run -dp 3000:3000 \
  -w /app -v "$(pwd):/app" \
  --network todo-app \
  -e MYSQL_HOST=mysql \
  -e MYSQL_USER=root \
  -e MYSQL_PASSWORD=secret \
  -e MYSQL_DB=todos \
  getting-started \
  sh -c "yarn install && yarn run dev"

就使得托管应用的服务器与MySQL在同一网络(todo-app)下。此时如果在页面上触发能让MySQL数据库发生变化的操作,MySQL中对应表中的内容也将会发生变化。

小坑 我们的应用在连接数据库时可能会出现Host '172.21.0.3' is not allowed to connect to this MySQL server这样的提示,即应用无权连接到数据库。这时我们需要进入运行数据库的容器,来调整一下允许用户登录的Host - 默认Host为localhost,即只允许用户在本地登录。

首先进入容器并登陆MySQL

docker exec -it <mysql-container-id> mysql -p

执行

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'secret' WITH GRANT OPTION;
FLUSH PRIVILEGES;

来让root用户可以通过任意Host进行登录。