当前位置:   article > 正文

一、mac 安装及使用docker

一、mac 安装及使用docker

一、Docker是什么

Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。它是目前最流行的 Linux 容器解决方案。

Docker 将应用程序与该程序的依赖,打包在一个image文件里面。

运行这个文件,就会生成一个虚拟容器。

程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。

 

1、Docker 把应用程序及其依赖,打包在 image 文件里面。只有通过这个文件,才能生成 Docker 容器。image 文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。同一个 image 文件,可以生成多个同时运行的容器实例。

2、image 是二进制文件。实际开发中,一个 image 文件往往通过继承另一个 image 文件,加上一些个性化设置而生成。举例来说,你可以在 Ubuntu 的 image 基础上,往里面加入 Apache 服务器,形成你的 image。

image 文件是通用的,一台机器的 image 文件拷贝到另一台机器,照样可以使用。一般来说,为了节省时间,我们应该尽量使用别人制作好的 image 文件,而不是自己制作。即使要定制,也应该基于别人的 image 文件进行加工,而不是从零开始制作。

3、为了方便共享,image 文件制作完成后,可以上传到网上的仓库。Docker 的官方仓库 Docker Hub 是最重要、最常用的 image 仓库。此外,出售自己制作的 image 文件也是可以的。

有了 Docker,就不用担心环境问题。

总体来说,Docker 的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。

二、Docker 的用途

Docker 的主要用途,目前有三大类。

(1)提供一次性的环境。比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境。

(2)提供弹性的云服务。因为 Docker 容器可以随开随关,很适合动态扩容和缩容。

(3)组建微服务架构。通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构。

三、安装:

下载地址:

Empowering App Development for Developers | Docker

Get Started with Docker | Docker

Install Docker Desktop on Mac | Docker Documentation

用户手册:

Docker Desktop for Mac user manual | Docker Documentation

Docker 是服务器----客户端架构。命令行运行docker命令的时候,需要本机有 Docker 服务。如果这项服务没有启动,可以用下面的命令启动

  1. # service 命令的用法
  2. $ sudo service docker start
  3. # systemctl 命令的用法
  4. $ sudo systemctl start docker

四、配置镜像

4.1为什么要配置镜像:

因为docker服务器在国外,基于网速与“和谐墙”的问题,所以我们在国内操作国外镜像可能无法正常拉取,这需要我们为docker设置国内的阿里云镜像加速器。

4.2配置镜像

Preferences--Docker Engine

  1. {
  2. "debug": true,
  3. "experimental": false,
  4. "registry-mirrors": [
  5. "https://e29lwva9.mirror.aliyuncs.com"
  6. ]
  7. }

然后重启一下

4.3查看是否配置成功

在终端输入

docker info

查看结果

 镜像配置成功

六、运行docker程序,实例:hello world

下面,我们通过最简单的 image 文件"hello world",感受一下 Docker。

需要说明的是,国内连接 Docker 的官方仓库很慢,还会断线,需要将默认仓库改成国内的镜像网站。

首先,运行下面的命令,将 image 文件从仓库抓取到本地。

docker image pull library/hello-world

上面代码中,docker image pull是抓取 image 文件的命令。library/hello-world是 image 文件在仓库里面的位置,其中library是 image 文件所在的组,hello-world是 image 文件的名字。

由于 Docker 官方提供的 image 文件,都放在library组里面,所以它的是默认组,可以省略。因此,上面的命令可以写成下面这样。

docker image pull hello-world

抓取成功以后,就可以在本机看到这个 image 文件了。

docker images

现在,运行这个 image 文件。

docker container run hello-world

docker container run命令会从 image 文件,生成一个正在运行的容器实例。

注意,docker container run命令具有自动抓取 image 文件的功能。

如果发现本地没有指定的 image 文件,就会从仓库自动抓取。

因此,前面的docker image pull命令并不是必需的步骤。

如果运行成功,你会在屏幕上读到下面的输出。

  1. a58@58deMacBook-Pro-2 ~ % docker container run hello-world
  2. Hello from Docker!
  3. This message shows that your installation appears to be working correctly.

输出这段提示以后,hello world就会停止运行,容器自动终止。

有些容器不会自动终止,因为提供的是服务。比如,安装运行 Ubuntu 的 image,就可以在命令行体验 Ubuntu 系统。

  1. $ docker container run -it ubuntu bash

对于那些不会自动终止的容器,必须使用docker container kill 命令手动终止。

  1. $ docker container kill [containID]

6.2 第一次运行命令 docker run ubuntu echo hello world

  1. a58@58deMacBook-Pro-2 ~ % docker run ubuntu echo hello world
  2. Unable to find image 'ubuntu:latest' locally
  3. docker: Error response from daemon: pull access denied for cs, repository does not exist or may require 'docker login': denied: requested access to the resource is denied.
  4. See 'docker run --help'.

运行失败,原因:

docker在运行一个容器之前,会先看本地是否有容器需要的image,如果没有的话会去远端下载。

运行完成之后,会在本地生成一个名为ubuntu的imge

我们再次执行

  1. a58@58deMacBook-Pro-2 ~ % docker run ubuntu echo hello world
  2. hello world

在 ubuntu这个image里,运行了echo hello world 这个命令,输出了hello world 

查看本地所有的images

docker images

  1. a58@58deMacBook-Pro-2 ~ % docker images
  2. REPOSITORY               TAG       IMAGE ID       CREATED        SIZE
  3. docker/getting-started   latest    adfdb308d623   3 weeks ago    27.4MB
  4. ubuntu                   latest    d5ca7a445605   4 months ago   65.6MB
  5. hello-world              latest    18e5af790473   5 months ago   9.14kB

七、容器文件

image 文件生成的容器实例,本身也是一个文件,称为容器文件。也就是说,一旦容器生成,就会同时存在两个文件: image 文件和容器文件。而且关闭容器并不会删除容器文件,只是容器停止运行而已。

  1. # 列出本机正在运行的容器
  2. $ docker container ls
  3. # 列出本机所有容器,包括终止运行的容器
  4. $ docker container ls --all

上面命令的输出结果之中,包括容器的 ID (containerID)。很多地方都需要提供这个 ID,比如上一节终止容器运行的docker container kill命令。

终止运行的容器文件,依然会占据硬盘空间,可以使用docker container rm命令删除。

docker container rm [containerID]

运行上面的命令之后,再使用docker container ls --all命令,就会发现被删除的容器文件已经消失了。

7.2容器与image的关系

image id 是固定不变的。根据同一个image生成的不同容器,容器id containerID 是不同的

八、 docker启动nginx容器

  1. a58@58deMacBook-Pro-2 ~ % docker run nginx
  2. Unable to find image 'nginx:latest' locally

docker run nginx ,执行失败。

docker在运行一个容器之前,会先看本地是否有容器需要的image,如果没有的话会去远端下载。

再次运行:

  1. a58@58deMacBook-Pro-2 ~ % docker run -p 8080:80 -d nginx
  2. 612195861a8cd79ed5202c7eab581a86f78d0284672ab0662450236bebfbf696

运行成功

命令解释:

  1. -p 8080:80 端口映射,将image的80端口,映射到本地8080端口
  2. -d 允许这个程序直接返回

  docker ps 查看我们刚刚启动docker容器的信息

  1. a58@58deMacBook-Pro-2 ~ % docker ps
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. 612195861a8c nginx "/docker-entrypoint.…" 5 minutes ago Up 5 minutes 0.0.0.0:8080->80/tcp interesting_allen

容器的id

CONTAINER ID :612195861a8c 

端口映射关系

PORTS: 0.0.0.0:8080->80/tcp

我们在浏览器访问地址:

http://localhost:8080/

 我们在当前浏览器启动了一个nginx

3.3 我们在本地创建一个index.html文件

index.html

  1. <html>
  2. <h1> Docker is fun!</h1>
  3. </html>

将index.htm复制到ningx容器中

docker cp index.html 612195861a8c://usr/share/nginx/html

612195861a8c 为容器的id。

我们再次访问

http://localhost:8080/

现在访问的就是我们刚刚复制过去的index.htm文件

停止docker容器

docker stop +容器id

  1. a58@58deMacBook-Pro-2 ~ % docker stop 612195861a8c
  2. 612195861a8c

停止docker容器后,再次访问 http://localhost:8080/

显示无法访问此网站

再次启动容器  docker run -p 8080:80 -d nginx

  1. a58@58deMacBook-Pro-2 ~ % docker run -p 8080:80 -d nginx
  2. b77bac0b212baaa7e33564ea623b09be58b06838a6fda4cf0612c397eaa11dad

查看详细信息 docker ps

  1. a58@58deMacBook-Pro-2 ~ % docker ps
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. b77bac0b212b nginx "/docker-entrypoint.…" 12 seconds ago Up 10 seconds 0.0.0.0:8080->80/tcp strange_mcnulty

发现,容器的id变了。

再次访问 

http://localhost:8080/

此时访问的地址,展示的是nginx缺省的页面,而不是刚刚我们复制的index.htm页面。

这是因为在容器的改动,都是暂时的,不会被保存。

九、如何保存容器内的改动?

我们再次把index.html,复制到刚刚的容器中

docker cp index.html 384c7a8e8028://usr/share/nginx/html 

384c7a8e8028是容器id

访问:

http://localhost:8080/

9.1 使用commit命令来保存

docker commit -m '增加index' 384c7a8e8028

最后面的384c7a8e8028是容器的id

  1. a58@58deMacBook-Pro-2 ~ % docker commit -m '增加index' 384c7a8e8028
  2. sha256:14a1e785e7c14821e051c1939b2caeee8bc450a7e710ec959dd1ea085c1bc6c7

使用commit提交改动后,会产生一个新的image id。

查看所有的images

docker images

 此时新增了一个image,但是 名字和TAG都是为空(因为我们刚刚commit的时候没有加名字)

再次重复执行一下刚刚的操作

docker cp index.html 384c7a8e8028://usr/share/nginx/html

nginx-fun 是我们给的名字

docker commit -m '增加index' 384c7a8e8028 nginx-fun

再次查看所有的image

 docker images

9.2 删除image

删除名称为none的image

docker rmi 14a1e785e7c1

rmi: remove image 的缩写

14a1e785e7c1: 要被删除的image的id

9.3 删除容器 

查看正在运行的docker 容器

docker ps

停止正在运行的docker容器

docker stop 384c7a8e8028

 384c7a8e8028容器id  CONTAINER ID

查看docker所有的容器(运行中的+历史的)

docker ps -a

删除

删除2个 

docker rm 3a485ba7386e cb77a4f75e2e

再次查看所有

docker ps -a

被删除的不在了

十、docker命令总结

命令用途
docker pull远程拉取image
docker build创建image
docker images列出本地所有的image
docker run运行容器container
docker ps列出当前运行的容器container
docker rm删除已经结束的容器container
docker cp在本地和容器之间拷贝文件
docker commit保存改动生成新的image
docker rmi删除image

十一、Dockerfile 文件,自创镜像

学会使用 image 文件以后,接下来的问题就是,如何可以生成 image 文件?如果你要推广自己的软件,势必要自己制作 image 文件。

这就需要用到 Dockerfile 文件。它是一个文本文件,用来配置 image。Docker 根据 该文件生成二进制的 image 文件。

下面通过一个实例,演示如何编写 Dockerfile 文件。

准备一个Dockerfile 文件,文件内容如下(只有三行):

  1. FROM alpine:latest
  2. MAINTAINER cs
  3. CMD echo 'hello docker'

内容解释:

FROM alpine:latest   我们创造的新镜像依赖的基础镜像
MAINTAINER cs   没有特殊的功能,就是标注作者是cs
CMD echo 'hello docker'   运行一个命令 

创建一个目录 d1

  1. mkdir d1
  2. cd d1

创建Dockerfile文件

touch Dockerfile

这里文件名称,约定成俗的是Dockerfile,也可以用其他名字,但是不建议

编辑文件:

vim Dockerfile
  1. FROM alpine:latest
  2. MAINTAINER cs
  3. CMD echo 'hello docker'

11.1用docker命令构建新的image

docker build -t hello_docker .

命令解释:

-t 打标签,标签名称为hell_docker

.  点是路径名,将路径内所有的文件都打包进image

构建成功后,查看我们刚刚创建的image

docker images hello_docker

运行我们的image 

docker run hello_docker

11.2 第二个Dockerfile

Dockerfile 文件内容:

  1. FROM ubuntu
  2. MAINTAINER cs
  3. RUN sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
  4. RUN apt-get update
  5. RUN apt-get install -y nginx
  6. COPY index.html /var/www/html
  7. ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
  8. EXPOSE 80

FROM ubuntu        基础镜像ubuntu
MAINTAINER cs   创作者

RUN sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list

使用国内镜像,快一点


RUN apt-get update  更新ubuntu的程序库
RUN apt-get install -y nginx  安装nginx
COPY index.html /var/www/html  拷贝本地index.htm文件到容器 /var/www/html 路径下 
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]  给出一个容器的入口,将nginx作为一个前台程序进行
EXPOSE 80 端口号

  1. 创建目录
  2. mkdir dockerfiler2
  3. cd dockerfiler2
  4. 创建文件
  5. touch Dockerfile
  6. 编辑文件
  7. vi Dockerfile

创建index.html

  1. 在dockerfiler2目录下,创建index.html文件
  2. touch index.html
  3. vi index.html

index.html随便输入一个行内容  大家好 

开始构建

docker build -t cs/hello-nginx .

运行刚刚创建的image

docker run -d -p 83:80 cs/hello-nginx

-d 作为守护进程

-p 83:80 映射到本地83端口

访问一下刚刚的容器

  1. a58@58deMacBook-Pro-2 dockerfiler2 % curl http://localhost:83
  2. 大家好

11.3Dockerfile语法

命令用途
FROMbase image
RUN在容器内执行命令
ADD往容器内添加文件(可以添加远程文件)
COPY往容器内拷贝文件
CMD给容器添加一个执行入口
EXPOSE暴露端口
WORKDIR指定运行命令的路径
MAINTAINER维护者
ENV给容器里面环境设定变量
ENTRYOINIT设定容器入口
USER指定执行该命令的用户
VOLUME

十二、实例:制作自己的 Docker 容器

下面我以 koa-demos 项目为例,介绍怎么写 Dockerfile 文件,实现让用户在 Docker 容器里面运行 Koa 框架。

作为准备工作,请先下载源码

  1. git clone https://github.com/ruanyf/koa-demos.git
  2. cd koa-demos

12.1 编写 Dockerfile 文件

首先,在项目的根目录下,新建一个文本文件.dockerignore,写入下面的内容

  1. .git
  2. node_modules
  3. npm-debug.log

上面代码表示,这三个路径要排除,不要打包进入 image 文件。如果你没有路径要排除,这个文件可以不新建。

然后,在项目的根目录下,新建一个文本文件 Dockerfile,写入下面的内容

  1. FROM node:8.4
  2. COPY . /app
  3. WORKDIR /app
  4. RUN npm install --registry=https://registry.npm.taobao.org
  5. EXPOSE 3000

上面代码一共五行,含义如下。

  1. FROM node:8.4:该 image 文件继承官方的 node image,冒号表示标签,这里标签是8.4,即8.4版本的 node。
  2. COPY . /app:将当前目录下的所有文件(除了.dockerignore排除的路径),都拷贝进入 image 文件的/app目录。
  3. WORKDIR /app:指定接下来的工作路径为/app。
  4. RUN npm install:在/app目录下,运行npm install命令安装依赖。注意,安装后所有的依赖,都将打包进入 image 文件。
  5. EXPOSE 3000:将容器 3000 端口暴露出来, 允许外部连接这个端口。

12.2 创建 image 文件

有了 Dockerfile 文件以后,就可以使用docker image build命令创建 image 文件了

  1. $ docker image build -t koa-demo .
  2. # 或者
  3. $ docker image build -t koa-demo:0.0.1 .

上面代码中,-t参数用来指定 image 文件的名字,后面还可以用冒号指定标签。如果不指定,默认的标签就是latest。最后的那个点表示 Dockerfile 文件所在的路径,上例是当前路径,所以是一个点。

如果运行成功,就可以看到新生成的 image 文件koa-demo了。

docker images

  1. a58@58deMacBook-Pro-2 koa-demos % docker images
  2. REPOSITORY TAG IMAGE ID CREATED SIZE
  3. koa-demo latest 1dc92a9cbdb2 13 seconds ago 676MB
  4. docker/getting-started latest adfdb308d623 3 weeks ago 27.4MB

12.3 生成容器

docker container run命令会从 image 文件生成容器。

  1. $ docker container run -p 8000:3000 -it koa-demo /bin/bash
  2. # 或者
  3. $ docker container run -p 8000:3000 -it koa-demo:0.0.1 /bin/bash

上面命令的各个参数含义如下:

  • -p参数:容器的 3000 端口映射到本机的 8000 端口。
  • -it参数:容器的 Shell 映射到当前的 Shell,然后你在本机窗口输入的命令,就会传入容器。
  • koa-demo:0.0.1:image 文件的名字(如果有标签,还需要提供标签,默认是 latest 标签)。
  • /bin/bash:容器启动以后,内部第一个执行的命令。这里是启动 Bash,保证用户可以使用 Shell。

如果一切正常,运行上面的命令以后,就会返回一个命令行提示符。

  1. root@66d80f4aaf1e:/app#

这表示你已经在容器里面了,返回的提示符就是容器内部的 Shell 提示符。执行下面的命令。

  1. root@66d80f4aaf1e:/app# node demos/01.js

这时,Koa 框架已经运行起来了。打开本机的浏览器,访问 http://127.0.0.1:8000,网页显示"Not Found",这是因为这个 demo 没有写路由。

这个例子中,Node 进程运行在 Docker 容器的虚拟环境里面,进程接触到的文件系统和网络接口都是虚拟的,与本机的文件系统和网络接口是隔离的,因此需要定义容器与物理机的端口映射(map)。

现在,在容器的命令行,按下 Ctrl + c 停止 Node 进程,然后按下 Ctrl + d (或者输入 exit)退出容器。此外,也可以用docker container kill终止容器运行。

  1. # 在本机的另一个终端窗口,查出容器的 ID
  2. $ docker container ls
  3. # 停止指定的容器运行
  4. $ docker container kill [containerID]

容器停止运行之后,并不会消失,用下面的命令删除容器文件。

  1. # 查出容器的 ID
  2. $ docker container ls --all
  3. # 删除指定的容器文件
  4. $ docker container rm [containerID]

也可以使用docker container run命令的--rm参数,在容器终止运行后自动删除容器文件。

  1. $ docker container run --rm -p 8000:3000 -it koa-demo /bin/bash

12.4 CMD 命令

上一节的例子里面,容器启动以后,需要手动输入命令node demos/01.js。我们可以把这个命令写在 Dockerfile 里面,这样容器启动以后,这个命令就已经执行了,不用再手动输入了。

  1. FROM node:8.4
  2. COPY . /app
  3. WORKDIR /app
  4. RUN npm install --registry=https://registry.npm.taobao.org
  5. EXPOSE 3000
  6. CMD node demos/01.js

上面的 Dockerfile 里面,多了最后一行CMD node demos/01.js,它表示容器启动后自动执行node demos/01.js

你可能会问,RUN命令与CMD命令的区别在哪里?简单说,RUN命令在 image 文件的构建阶段执行,执行结果都会打包进入 image 文件;CMD命令则是在容器启动后执行。另外,一个 Dockerfile 可以包含多个RUN命令,但是只能有一个CMD命令。

注意,指定了CMD命令以后,docker container run命令就不能附加命令了(比如前面的/bin/bash),否则它会覆盖CMD命令。现在,启动容器可以使用下面的命令。

  1. $ docker container run --rm -p 8000:3000 -it koa-demo:0.0.1

12.5 发布 image 文件

容器运行成功后,就确认了 image 文件的有效性。这时,我们就可以考虑把 image 文件分享到网上,让其他人使用。

首先,去 hub.docker.com 或 cloud.docker.com 注册一个账户。然后,用下面的命令登录。

  1. $ docker login

接着,为本地的 image 标注用户名和版本。

  1. $ docker image tag [imageName] [username]/[repository]:[tag]
  2. # 实例
  3. $ docker image tag koa-demos:0.0.1 ruanyf/koa-demos:0.0.1

也可以不标注用户名,重新构建一下 image 文件。

  1. $ docker image build -t [username]/[repository]:[tag] .

最后,发布 image 文件。

  1. $ docker image push [username]/[repository]:[tag]

发布成功以后,登录 hub.docker.com,就可以看到已经发布的 image 文件。

十四、其他有用的命令

docker 的主要用法就是上面这些,此外还有几个命令,也非常有用。

(1)docker container start

前面的docker container run命令是新建容器,每运行一次,就会新建一个容器。同样的命令运行两次,就会生成两个一模一样的容器文件。如果希望重复使用容器,就要使用docker container start命令,它用来启动已经生成、已经停止运行的容器文件。

  1. $ docker container start [containerID]

(2)docker container stop

前面的docker container kill命令终止容器运行,相当于向容器里面的主进程发出 SIGKILL 信号。而docker container stop命令也是用来终止容器运行,相当于向容器里面的主进程发出 SIGTERM 信号,然后过一段时间再发出 SIGKILL 信号。

  1. $ docker container stop [containerID]

这两个信号的差别是,应用程序收到 SIGTERM 信号以后,可以自行进行收尾清理工作,但也可以不理会这个信号。如果收到 SIGKILL 信号,就会强行立即终止,那些正在进行中的操作会全部丢失。

(3)docker container logs

docker container logs命令用来查看 docker 容器的输出,即容器里面 Shell 的标准输出。如果docker run命令运行容器的时候,没有使用-it参数,就要用这个命令查看输出。

  1. $ docker container logs [containerID]

(4)docker container exec

docker container exec命令用于进入一个正在运行的 docker 容器。如果docker run命令运行容器的时候,没有使用-it参数,就要用这个命令进入容器。一旦进入了容器,就可以在容器的 Shell 执行命令了。

  1. $ docker container exec -it [containerID] /bin/bash

(5)docker container cp

docker container cp命令用于从正在运行的 Docker 容器里面,将文件拷贝到本机。下面是拷贝到当前目录的写法。

  1. $ docker container cp [containID]:[/path/to/file] .

十五、镜像分层

镜像是分层被存储的,而不是作为整个文件被存储的。

Dockerfile中的每一行都产生一个新增

已经存在image里面的层,是只读的

当image被容器运行,会产生一个新层 容器层container layer ,这一层是可读可写的。 

分层的好处:

A image 有10层,B image有7层,其中5层是共享的,节省了空间。

十六、Volume  docker的存储技术

提供独立于容器之外的持久化存储

在容器中的改动,是不会被保存的。Volume提供了一个比较方便的,持久化的。

比如运行一个数据库容器的操作,数据库的数据应该是被持久化的。Volume就可以做这些,并且可以提供给容器之间的共享数据。

16.1 Volume

Volume

方式一  通过-v命令

docker run -d --name nginx -v /usr/share/nginx/html nginx

--name nginx 给他命名为nginx

查看容器的所有信息

docker inspect nginx

宿主机的这个路径 "Source": "/var/lib/....挂载到了 容器的内部这个地址/usr/share/nginx/html

在终端查看 “/var/lib/docker/volumes/7597264b02449c89e469f00198fa48a803883a7c6cf403c97e005a5d747c3326/_data’ 这个地址

ls /var/lib/docker/volumes/7597264b02449c89e469f00198fa48a803883a7c6cf403c97e005a5d747c3326/_data

提示No such file or directory,

参考博客:





docker的简单使用:mac下docker配置http镜像源,并pull和push镜像_星痕の博客-CSDN博客_docker http pull

mac docker配置镜像的方式_峰会路转的博客-CSDN博客_docker mac 设置镜像

 Mac 下如何切换 Docker 容器镜像?(更改阿里镜像)_hedeqiang-CSDN博客

Docker 入门教程 - 阮一峰的网络日志

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号