之前也有听说过docker但是因为没有具体的业务接触所以并没有具体的去了解过,最近手头的工作也暂时没有那么急所以趁着时间来看下。
系统:CentOS 7.6 64位
yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的
yum install -y yum-utils device-mapper-persistent-data lvm2默认安装最新版本
yum install docker-ce安装某特定版本需增加版本号(如18.06.3.ce-3.el7)
yum install docker-ce-18.06.3.ce将 docker 的权限移交给非 root 用户,这样使用 docker 就不需要每次都 sudo 了:
sudo usermod -aG docker $USER注销用户或者重启之后就会生效。然后通过 systemd 服务配置 Docker 开机启动:
systemctl enable docker如果存在Client和Server则成功
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H3FrxuNg-1602064860477)(https://tothers.top1buyer.com/WeChatf12c620346c9dac34e1fb7e84c0bb781.png)]
默认的镜像仓库 Docker Hub 在国外,国内拉取速度比较感人。建议参考这篇文章配置镜像加速
到这里前期的准备和环境安装工作就完成了,下面就开始上手实践吧!
按照惯例,我们运行胰腺癌来自Docker的Hello World:
docker run hello-world这个过程中Docker做了以下事情:
检查本地是否有指定的 hello-world:latest 镜像(latest 是镜像标签,后面会细讲),如果没有,执行第 2 步,否则直接执行第 3 步。本地没有指定镜像(Unable to find xxx locally),从 Docker Hub 下载到本地。根据本地的 hello-world:latest 镜像创建一个新的容器并运行其中的程序。运行完毕后,容器退出,控制权返回给用户。运行以下命令:
docker run -p 8080:80 nginx运行之后,你会发现一直卡住,也没有任何输出,但放心你的电脑并没有死机。让我们打开浏览器访问localhost:8080(如果像我一样用的服务器可以打开服务器域名:8080来查看)
打开链接会看到Welecome to nginx!我们可以继续访问一些不存在的路由,比如localhost:8080/index,同样会提示404。这个时候我们运行
docker ps可以看到Docker容器的输出,就有内容了。 总结下刚才Docker做的事情:
检查本地是否有指定的 nginx:latest 镜像(关于 latest 标签,后面会细讲),如果没有,执行第 2 步,否则直接执行第 3 步。本地没有指定镜像(Unable to find xxx locally),从 Docker Hub 下载到本地。根据本地的 nginx:latest 镜像创建一个新的容器,并通过 **-p(--publish**)参数建立本机的 8080 端口与容器的 80 端口之间的映射,然后运行其中的程序。Nginx 服务器程序保持运行,容器也不会退出。看上去很酷,不过像 Nginx 服务器这样的进程我们更希望把它抛到后台一直运行。按 Ctrl + C 退出当前的容器,然后再次运行以下命令:
docker run -p 8080:80 --name my-nginx -d nginx注意到与之前不同的是,我们:
加了一个参数 --name,用于指定容器名称为 my-nginx。加了一个选项 -d(–detach),表示 “后台运行”。{% blockquote %} 容器的名称必须是唯一的,如果已经存在同一名称的容器(即使已经不再运行)就会创建失败。如果遇到这种情况,可以删除之前不需要的容器(后面会讲解怎么删除)。 {% endblockquote %}
Docker 会输出一串长长的 64 位容器 ID,然后把终端的控制权返回给了我们。我们试着访问 localhost:8080(服务器域名:8080),还能看到那一串熟悉的 Welcome to nginx!,说明服务器真的在后台运行起来了。
那我们怎么管理这个服务器呢?就像熟悉的 UNIX ps 命令一样,docker ps 命令可以让我们查看当前容器的状态:
docker ps输出结果是这样的: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5zj92rSg-1602064860480)(https://tothers.top1buyer.com/docker-1-5.png)]
从这张表中,就可以清晰地看到了我们在后台运行的 Nginx 服务器容器的一些信息:
容器 ID(Container ID)为 f104751ca7db(你机器上的可能不一样)。所用镜像(Image)为 nginx。运行命令 / 程序(Command)为 nginx -g 'daemon of…,这个是 Nginx 镜像自带的运行命令,暂时不用关心。创建时间(Created)为 an hour ago(一小时之前)。当前状态(Status)为 Up About an hout(已运行 超过一小时)。端口(Ports)为 0.0.0.0:8080->80/tcp,意思是访问本机的 0.0.0.0:8080 的所有请求会被转发到该容器的 TCP 80 端口。名称(Names)为刚才指定的 my-nginx。如果我们要让容器停下来,通过 docker stop 命令指定容器名称或 ID 进行操作即可,命令如下:
docker stop my-nginx运行以下命令,让我们进入到一个 Ubuntu 镜像中:
docker run -it --name dreamland ubuntu可以看到我们加了 -it 选项,等于是同时指定 -i(–interactive,交互式模式)和 -t(–tty,分配一个模拟终端) 两个选项。以上命令的输出如下:
这时我们已经在这个Ubuntu镜像中了,可以运行一些命令来看一下
whoami ls按 Ctrl + D (或者输入 exit 命令)即可退出。你可以在 docker ps 的终端再次检查容器是否已经被关闭了。
我们刚才创建的 Docker 容器也只是用于初步探索,后续不会再用到。由于 Docker 容器是直接存储在我们本地硬盘上的,及时清理容器也能够让我们的硬盘压力小一些。我们可以通过以下命令查看所有容器(包括已经停止的):
docker ps -a类似 Shell 中的 rm 命令,我们可以通过 docker rm 命令销毁容器,例如删除我们之前创建的 dreamland 容器:
docker rm dreamland # 或者指定容器 ID,记得替换成自己机器上的 # docker rm f104751ca7db(你机器上的可能不一样)。但如果我们想要销毁所有容器怎么办?一次次输入 docker rm 删除显然不方便,可以通过以下命令轻松删除所有容器:
docker rm $(docker ps -aq)docker ps -aq 会输出所有容器的 ID,然后作为参数传给 docker rm 命令,就可以根据 ID 删除所有容器啦。
删除运行中的容器
docker rm -f dreamland同样的,我们可以删除所有容器,无论处于什么状态:
docker rm -f $(docker ps -aq)在之前的步骤中,我们体验了别人为我们提前准备好的镜像(例如 hello-world、nginx 和 ubuntu),这些镜像都可以在 Docker Hub 镜像仓库中找到。在这一步,我们将开始筑梦之旅:学习如何容器化(Containerization)你的应用。
运行以下命令来获取代码,然后进入项目:
git clone -b start-point https://github.com/tuture-dev/docker-dream.git cd docker-dream如果没有安装git,可以运行
yum install git来安装,也可以到GIT官网来查看如何安装你所对应的平台。
在这一步中,我们将容器化这个用 React 编写的前端应用,用 Nginx 来提供前端页面的访问。
什么是容器化:
编写代码:我们已经提供了写好的代码。构建镜像。创建和运行容器:通过容器的方式运行我们的应用。构建 Docker 镜像主要包括两种方式:
手动:根据现有的镜像创建并运行一个容器,进入其中进行修改,然后运行 docker commit 命令根据修改后的容器创建新的镜像。自动:创建 Dockerfile 文件,指定构建镜像的命令,然后通过 docker build 命令直接创建镜像。我们先把前端项目 client 构建成一个静态页面。确保你的机器上已经安装 Node 和 npm(点击这里下载,或使用 nvm),然后进入到 client 目录下,安装所有依赖,并构建项目:
cd client npm install npm run build如果安装node和npm出现问题的可以看下我之前的这篇文章Linux安装Node。
等待一阵子后,你应该可以看到 client/build 目录,存放了我们要展示的前端静态页面。
创建 Nginx 配置文件 client/config/nginx.conf,代码如下:
server { listen 80; root /www; index index.html; sendfile on; sendfile_max_chunk 1M; tcp_nopush on; gzip_static on; location / { try_files $uri $uri/ /index.html; } }上面的配置大致意思是:监听 80 端口,网页根目录在 /www,首页文件是 index.html,如果访问 / 则提供文件 index.html。
然后就是这一步骤中最重要的代码:Dockerfile!创建 client/Dockerfile 文件,代码如下:
FROM nginx:1.13 # 删除 Nginx 的默认配置 RUN rm /etc/nginx/conf.d/default.conf # 添加自定义 Nginx 配置 COPY config/nginx.conf /etc/nginx/conf.d/ # 将前端静态文件拷贝到容器的 /www 目录下 COPY build /www可以看到我们用了 Dockerfile 中的三个指令:
FROM 用于指定基础镜像,这里我们基于 nginx:1.13 镜像作为构建的起点。RUN 命令用于在容器内运行任何命令(当然前提是命令必须存在)。COPY 命令用于从 Dockerfile 所在的目录拷贝文件到容器指定的路径。现在可以来构建我们的镜像了,运行以下命令:
# 如果你已经在 client 目录中 #(注意最后面有个点,代表当前目录) docker build -t dream-client . # 如果你回到了项目根目录 docker build -t dream-client client可以看到我们指定了 -t(–tag,容器标签)为 dream-client,最后指定了构建容器的上下文目录(也就是 当前目录 . 或 client)。
运行以上的命令之后,你会发现:
Sending build context to Docker daemon 289.4MB接着运行了一系列的 Step(4 个),然后提示镜像构建成功。
为什么这个构建上下文(Build Context)这么大?因为我们把比 “黑洞” 还 “重” 的 node_modules 也加进去了!(忍不住想起了下面这张图)
Docker 提供了类似 .gitignore 的机制,让我们可以在构建镜像时忽略特定的文件或目录。创建 client/.dockerignore 文件(注意 dockerignore 前面有一个点):
node_modules再次运行构建命令:
docker build -t dream-client .可以看到这次只有1.217MB,而且速度也明显快了很多.
终于到了容器化的最后一步 —— 创建并运行我们的容器!通过以下命令运行刚才创建的 dream-client 镜像:
docker run -p 8080:80 --name client -d dream-client与之前类似,我们还是设定端口映射规则为 8080:80,容器名称为 client,并且通过 -d 设置为后台运行。然后访问 localhost:8080(老样子–服务器域名:8080): 可以看到如图所示的页面,表示容器运行成功.
在刚才的实战中,你也许已经注意到在拉取和构建镜像时,Docker 总是会为我们加上一个 :latest 标签,这个 :latest 的含义便是 “最新” 的意思。和软件的版本机制一样,镜像也可以通过标签实现 “版本化”。
实际上,我们完全可以在拉取或构建镜像时指定标签(通常被认为是一种好的做法):
docker pull nginx:1.13 docker build -t dream-client:1.0.0还可以给现有的镜像打上标签:
# 把默认的 latest 镜像打上一个 newest 标签 docker tag dream-client dream-client:newest # 甚至可以同时修改镜像的名称和标签 docker tag dream-client:1.0.0 dream-client2:latest可以看到,标签未必一定是版本,还可以是任何字符串(当然最好要有意义,否则过了一阵子你也不记得这个打了这个标签的容器有什么作用了)。
Dockerfile 实际上是默认名称,我们当然可以取一个别的名字,例如 myDockerfile,然后在构建镜像时指定 -f(–file)参数即可:
docker build -f myDockerfile -t dream-client .这里举两个经典的使用场景:
例如在 Web 开发时,分别创建 Dockerfile.dev 用于构建开发镜像,创建 Dockerfile.prod 构建生产环境下的镜像;在训练 AI 模型时,创建 Dockerfile.cpu 用于构建用 CPU 训练的镜像,创建 Dockerfile.gpu 构建用 GPU 训练的镜像。这篇文章是我跟着图灵社区的流程走了一遍所记录的过程,点击这里查看图灵社区