吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3713|回复: 1
收起左侧

[会员申请] 申请会员:笨宝

[复制链接]
吾爱游客  发表于 2020-5-9 10:05

1.申请ID:笨宝
2.个人邮箱: [email]1829913225@qq.com
3.原创技术:2020年最全的Docker v19.x入门手册

`第二次提交换了一篇文章不知道行不行, 如果这次还不行下次就发一篇关于编程的吧`

提示

首先非常感谢你能在闲暇之余点开了我的这篇文章,这篇文章因为是比较全面的Docker入门的一个教程,所以可能需要花费比较长的时间来阅读能比较多,所以如果方便的化你可以点击下面的【赞】或者【收藏】来阅读。最后非常感谢你的阅读,有什么问题可以评论留言,小编会在看到的第一时间给你回复,谢谢。

环境

  • centos7
  • docker19.x
目录

@[TOC]

什么是Docker

简单来说就是将应用程序部署到独立的容器,每个容器相当于一个小的linux系统。通过将容器进行打包成镜像,放到将镜像放到任何有Docker环境的系统上运行。

使用Go语言开发,基于Apache2.0开源协议。

Docker的优势

  • Docker提供简单的轻量的服务器部署。
  • 可以清楚的将开发人员与运维人员的职责分离。
  • 快速的开发生命周期。
  • 面向服务的架构,每个服务相互隔离。

Docker应用在哪里

  • 可以使用Docker容器开发后测试然后部署服务。
  • 创建相互隔离的运行环境。
  • 搭建测试环境,例如集群测试。

Docker容器的能力

  • 文件系统的隔离
  • 进程的隔离
  • 网络的隔离
  • 硬件资源的隔离和分组

Docker的核心组成

  • Docker Client 客户端
  • Docker Daemon 守护进程
  • Docker Image 镜像
  • Docker Container 容器
  • Docker Registry 仓库

Docker Client与Docker Daemon

Docker是C/S架构的程序,其中Docker Client扮演的是客户端,Docker Daemon扮演的是服务器端。

docker Client即可是在本机也可以在远程。

Docker Image

镜像好比容器的源代码,保存了容器启动的各种条件。

Docker将一些容器运行的系统与应用服务打包起来,通过联合加载的方式运行,这个打包起来的文件就成为镜像。

一个镜像可以放到另一个镜像的底部,最下面的镜像被称为基础镜像。

Docker Container

Docker的容器是Dacker的执行单元。

如果说镜像是打包,那么容器就是运行打包好的镜像。

Docker Registry

Docker仓库是用来保存Docker镜像的地方,分为:

  • 公有仓库 Docker Hub
  • 私有仓库

Docker入门操作

查看Docker的版本

$ docker version
$ docker info

搜索镜像

$ docker search <镜像名>

下载镜像

$ docker pull <用户名>/<镜像名>

启动容器

$ docker run <用户名>/<镜像名> [命令]
# 在启动的容器中安装Ping
# docker run <用户名>/<镜像名> apt-get install -y ping

查看运行的容器

$ docker ps

提交容器

$ docker commit <ID> <新名字>

查看指定ID的容器信息

$ docker inspect <ID>

查看有所有镜像

$ docker images

上传镜像到Docker Hub

先去https://hub.docker.com/官网申请一个docker hub 帐号

$ docker login # 登录Docker Hub
$ docker images #查看本地镜像
$ docker tag <镜像名> <用户名/镜像名> #将镜像转让我的账号下
$ docker push <用户名>/<镜像名>

安装Docker

ubuntu

第一步、检查是否支持Docker
$ uname -a 
#检查内核版本,必须高于3.10
$ ls -l /sys/class/misc/device-mapper
#检查存储驱动
第二步、安装docker
$ wget -qO- https://get.docker.com/ | sh

Centos7

sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
# 删除所有的Docker
sudo yum install -y yum-utils \
  device-mapper-persistent-data \
  lvm2
sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
# 使用 Docker 仓库进行安装
sudo yum install -y docker-ce docker-ce-cli containerd.io
# 如果提示您接受 GPG 密钥,请选是。

配置国内的镜像源

mkdir -p /etc/docker/
echo '{"registry-mirrors":["http://hub-mirror.c.163.com","https://registry.docker-cn.com"]}' > /etc/docker/daemon.json
systemctl daemon-reload && systemctl restart docker

容器的基本操作

普通容器

启动容器
$ docker run [<用户名>/]<镜像名>[:tag] [命令]
# 在启动的容器中安装Ping
# docker run <用户名>/<镜像名> apt-get install -y ping
启动交会容器
$ docker run [--name=<名称>] -i -t <镜像全名> /bin/bash
# -i 表示一直保持输入
# -t 表示打开tty终端
# --name 自定义名称
查看容器
$ docker ps [-a][-l]
# -a 查看所有的容器
# -l 查看最新的容器
查看指定ID的容器信息
$ docker inspect <ID>
启动/停止容器
$ docker [-i] start/stop <容器>
# -i表示持续输入
删除容器
$ docker rm <容器>

守护式容器

特点
  • 可以长期运行
  • 没有交互会话
  • 非常适合运行应用服务
命令
方法一
$ docker run -i -t <镜像> /bin/bash
# ctrl+p ctrl+q 退出bash,但没关闭容器
$ docker attach <正在运行容器>
# 重新进入正在运行的容器
方法二
$ docker run -d <镜像> <命令>
# -d 后台守护
查看容器日志
$ docker logs [-f][-t][--tail=n] 容器名
# -f 持续输出日志
# -t 日志加上时间戳
# --tail 返回最后的多少行
查看运行中的容器的进程
$ docker top <容器>
在运行的容器中启动新的进程
$ docker exec [-d][-i][-t] <容器名> [命令]
# -d 后台运行
# -i 交会运行
# -t 打开终端
停止容器
$ docker kill/stop <容器名>
# kill 直接停止
# stop 等待进程结束后停止
设置端口映射
$ docker run [-P][-p <port> | <port>:<port>] ...
# -P 映射容器中所有的端口
# -p 指定映射容器中某几个端口
# eg:
$ docker run -P -i -t ubuntu /bin/bash # 映射所有的端口
$ docker run -p 80 -i -t ubuntu /bin/bash # 映射80端口
$ docker run -p 8080:80 -i -t ubuntu /bin/bash # 将内部的80映射为8080
$ docker run -p 127.0.0.1:8080:80 -i -t ubuntu /bin/bash # 将内部的80端口映射为127.0.0.1:8080
# 注意:如果使用5、6行的方法进行映射,外部端口是随机分配的

管理镜像

概念

  • TAG:标签
    • 默认:latest
    • 这里多少为版本
    • eg:docker pull node:12.1.1 下载nodejs12.1.1版本

基本操作

显示所有的镜像
$ docker images [-q][-a] [仓库]
# -q 只看id
# -a 查看所有
查看镜像的详细
$ docker inspace <镜像名>
删除镜像
$ docker rmi [-f] <镜像名>
# -f 强制删除
查找镜像

方法1:镜像dockerhub上查找

方法2:

$ docker search [--automated][-no-trunc][-s <num>] <镜像名>
# --automated 只显示自动化选项 
# --no-trunc 不分页显示
# -s 显示的最低num的stat镜像
下载镜像
$ docker pull [-a] <镜像名>
# -a 下载匹配的所有镜像
标记镜像到某个仓库
$ docker tag  IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
上传镜像到DockerHub
$ docker images #查看本地镜像
$ docker tag <镜像名> <用户名/镜像名> #将镜像转让我的账号下
$ docker push <用户名/镜像名:Tag> #上传镜像

打包镜像

打包镜像有两种方法,推荐使用Dockerfie方法

使用commit打包

将部署好的容器进行打包。

$ docker commit [-a][-m][-p] <容器> <用户名/镜像名:版本>
# -a "" 镜像作者
# -m "" 打包备注
# -p 不停止镜像打包

使用Dockerfile文件打包

第一步:创建Dockerfile文件
#Dockerfile
FORM <基础镜像:Tag>
MAINTAINER <用户名> "联系方式" #新版本推荐使用 LABEL maintainer=value
RUN <linux命令>
...
EXPOSE <端口号>

说明:

这个EXPOSE指令实际上并不发布端口。它作为构建映像的人和运行容器的人之间的一种文档类型,而这些港口将被发布。若要在运行容器时实际发布端口,请使用-p旗上docker run若要发布和映射一个或多个端口,或-P标志以发布所有公开的端口,并将它们映射到高阶端口。

第二步:执行docker build命令
$ docker build [-t <镜像名>][--no-cache] <上下文路径>
# -t 镜像名称
# --no-cache 不使用缓存构建
# 上下文路径:
#   docker build 会将这个路径下所有的文件都打包上传给 Docker 引擎,
#   引擎内将这些内容展开后,就能获取到所有指定上下文中的文件了

注意不要将 / 作为上下文路径,因为他会把硬盘上所有的数据发给docker守护进程.

.dockerignore

创建.dockerignore文件,通过在该文件里添加匹配目录,可以在执行docker build -t xxx .命令时不上传匹配的目录。

#.dockerignore
*/temp* #匹配根目录下的子目录内所有的以temp开头的文件和文件夹
*/*/temp* #匹配根目录下的子目录的子目录内所有的以temp开头的文件和文件夹
**/temp* #匹配所有目录内的以temp开头的文件和文件夹
!my* #在排除文件及文件夹中允许上传my开头的文件及文件夹

Docker远程访问

Docker的配置文件在Centos7 /lib/systemd/system/docker.service

Docker守护进程Linux上配置文件的默认位置是/etc/docker/daemon.json或者通过--config-file参数可用于指定非默认位置。

Docker守护进程启动选项

  • -H unix:///var/run/docker.sock
  • -H tcp://host:port
  • -H fd://(默认)

配置开始

第一步:配置远程的Docker
vi /lib/systemd/system/docker.service

修改[Service]->ExecStart

ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H 0.0.0.0:2375

重启Docker

systemctl daemon-reload && systemctl restart docker
第二步:配置本地的系统环境变量
# windows
set DOCKER_HOST=tcp://远程ip

# Centos7
export DOCKER_HOST=tcp://远程ip

# 注意:以上配置都是临时的
测试
docker info
# 是否有结果
# 如果想更准确的测试,可以先将远程的Docker守护进程配置一个labels,然后执行命令即可

提示:

其实配置远程还有一种方法就是配置docker守护进程的配置文件daemon.json通过配置该文件下的hosts内的值也可以实现,需要注意的是这两种方法只需要使用其中一种即可。

# docker.service 
# [Service]->ExecStart
ExecStart=/usr/bin/dockerd  --containerd=/run/containerd/containerd.sock

# daemon.json
{
  "hosts":[
    "0.0.0.0:2375",
    "unix:///var/run/docker.sock"
  ]
}

Dockerfile指令

关键知识点

  • 上下文路径:

    上下文路径 是在使用docker build的时候最后一个参数锁指定的路径,通过该路径docker客户端会将该路径的下的所有文件都会发送给docker守护进程,然后在用户执行COPYADD的时候进行文件复制。如果有不想发送的文件可以向.dockerignore中写入匹配忽略路径。

  • RUN的执行过程

    RUN cd /app
    RUN echo "hello" > world.txt

    每一个 RUN 都是启动一个容器、执行命令、然后提交存储层文件变更。第一层 RUN cd /app 的执行仅仅是当前进程的工作目录变更,一个内存上的变化而已,其结果不会造成任何文件变更。而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更完全没关系,自然不可能继承前一层构建过程中的内存变化。

FORM

这个FROM指令初始化新构建阶段,并设置基础镜像以后的指令。因此Dockerfile必须有FROM指令。Image可以是任何有效的Image它特别容易从公共储存库下载。

FROM [--platform=<平台>] <image>[:<tag>] [AS <name>]
# --platform 指定平台 如,linux/amd64, linux/arm64,或windows/amd64;默认自动
# image 镜像名称
# tag 类似于版本
# As 起别名

ARG

ARG是在当前文件中设置变量,通过ARG定义变量可以在该文件内引用。

ARG VERSION=latest
FROM busybox:${VERSION} # FORM busybox:latest

LABEL

LABEL指令将元数据添加到Image中。一个LABEL是键值对。若要在LABEL值内使用引号和反斜杠,就像在命令行解析中一样。

LABEL <key>=<value> <key>=<value> <key>=<value> ...

例子:

LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
      that label-values can span multiple lines."

EXPOST

EXPOSE指令通知Docker容器在运行时侦听指定的网络端口。您可以指定端口是否侦听TCP或UDP,如果未指定协议,则默认为TCP。

实际上他并无卵用。这里指定的端口仅仅只是作为文档给其他的人看。

EXPOSE <port> [<port>/<protocol>...]
# port 端口号
# protocol 协议 tcp或udp

ENV

设置环境变量,该环境变量类似于linux中export的设置方法,区别在于他是永久的,所以他可以在后续的shell命令里使用该值。

ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...

例子:

ENV HI HELLO
RUN echo "${HI}" # Hello

COPY

复制指令,从上下文目录中复制文件或者目录到容器里指定路径。

COPY [--chown=<user>:<group>] <源路径1>...  <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",...  "<目标路径>"]
# [--chown=<user>:<group>] 用户改变复制到容器内文件的拥有者和属组。
# <源路径> 源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则

ADD

ADD 指令和 COPY 的使用格式一致(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:

  • ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
  • ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。

RUN

执行shell命令

CMD <shell 命令> 
CMD ["<可执行文件或命令>","<param1>","<param2>",...] 

CMD

类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:

  • CMD 在docker run 时运行。
  • RUN 是在 docker build。

作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。

注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。

CMD <shell 命令> 
CMD ["<可执行文件或命令>","<param1>","<param2>",...] 
CMD ["<param1>","<param2>",...]  # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数

ENTRYPOINT

类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。

但是, 如果运行 docker run 时使用了 --entrypoint 选项,此选项的参数可当作要运行的程序覆盖 ENTRYPOINT 指令指定的程序。

优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。

注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。

可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。

ENTRYPOINT ["<executeable>","<param1>","<param2>",...]

WORKDIR

指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。

docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。

WORKDIR <工作目录路径>

USER

用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。

USER <用户名>[:<用户组>]

HEALTHCHECK

用于指定某个程序或者指令来监控 docker 容器服务的运行状态。

HEALTHCHECK [选项] CMD <命令> #设置检查容器健康状况的命令
# HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK [选项] CMD <命令> # CMD 后面跟随的命令使用,可以参考 CMD 的用法。

ONBUILD

他不会在本次docker build的时候执行,会在子镜像构建的时候执行后面的<Dockerfile指令>。

ONBUILD <Dockerfile指令>

MAINTAINER (官方不推荐)

这个是将该镜像的维护人的信息写到镜像中,这是一个旧版的写法。

MAINTAINER <name> 

# 代替方案
LABEL maintainer=<name>

SHELL

通过该指令可以指定使用的shell解释器。

SHELL ["<Shell解释器>", "<默认参数>"]

VOLUME

定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。

在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。

作用:

  • 避免重要的数据,因容器重启而丢失,这是非常致命的。
  • 避免容器不断变大。
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>

Dockerfile的构建原理

docker会在执行每条Dockerfile的指令时会对FROM引入的基础镜像进行操作。

每操作一步会运行镜像->生成容器->修改容器->提交容器->生成新的镜像->删除容器,然后在新的镜像上继续修改提交,反复如此,最后生成出最终镜像。这些在中间生成的镜像被称为中间层镜像。

我们可以通过docker history <镜像名>来看生成镜像的过程。

Dockerfile源文件和上下文目录

2020/01/18  11:34                17 .dockerignore
2020/01/18  14:52               277 Dockerfile
2020/01/18  14:45    <DIR>          src
# 生成一个node的docker环境
FROM centos
LABEL maintainer="wm 15804854160@163.com"
RUN curl --silent --location https://rpm.nodesource.com/setup_12.x | bash - \
 && yum -y install nodejs
WORKDIR /root/project
COPY ./ ./
RUN cd src \
 && npm install
EXPOSE 8080:80

构建过程

E:\PJ\程序设计\docker容器技术\dome\nodejsDockerfile>docker build -t demo .
Sending build context to Docker daemon  22.02kB
Step 1/7 : FROM centos
 ---> 470671670cac
Step 2/7 : LABEL maintainer="wm 15804854160@163.com" #修改镜像
 ---> Running in 0a9bdf29772d #运行0a9bdf29772d容器
Removing intermediate container 0a9bdf29772d #删除0a9bdf29772d容器
 ---> 6bed20c22168 #生成新的镜像
Step 3/7 : RUN curl --silent --location https://rpm.nodesource.com/setup_12.x | bash -  && yum -y install nodejs
 ---> Running in a6f52a14bfbc

## Installing the NodeSource Node.js 12.x repo...

## Inspecting system...

+ rpm -q --whatprovides redhat-release || rpm -q --whatprovides centos-release || rpm -q --whatprovides cloudlinux-release || rpm -q --whatprovides sl-release
+ uname -m

## Confirming "el8-x86_64" is supported...

+ curl -sLf -o /dev/null 'https://rpm.nodesource.com/pub_12.x/el/8/x86_64/nodesource-release-el8-1.noarch.rpm'

## As yum will try to install Node.js from the AppStream repository
instead of the NodeSource repository, the AppStream's version of Node.js has to be disabled.
## Run `sudo yum module enable -y nodejs` to reactivate the AppStream's Node.js repository.

+ yum module disable -y nodejs
CentOS-8 - AppStream                            1.3 MB/s | 5.9 MB     00:04
CentOS-8 - Base                                 190 kB/s | 4.0 MB     00:21
CentOS-8 - Extras                               367  B/s | 2.1 kB     00:05
Dependencies resolved.
================================================================================
 Package           Architecture     Version             Repository         Size
================================================================================
Disabling modules:
 nodejs

Transaction Summary
================================================================================

Complete!

## Downloading release setup RPM...

+ mktemp
+ curl -sL -o '/tmp/tmp.w4Aojk1oBL' 'https://rpm.nodesource.com/pub_12.x/el/8/x86_64/nodesource-release-el8-1.noarch.rpm'

## Installing release setup RPM...

+ rpm -i --nosignature --force '/tmp/tmp.w4Aojk1oBL'

## Cleaning up...

+ rm -f '/tmp/tmp.w4Aojk1oBL'

## Checking for existing installations...

+ rpm -qa 'node|npm' | grep -v nodesource

## Run `sudo yum install -y nodejs` to install Node.js 12.x and npm.
## You may also need development tools to build native addons:
     sudo yum install gcc-c++ make
## To install the Yarn package manager, run:
     curl -sL https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
     sudo yum install yarn

Node.js Packages for Enterprise Linux 8 - x86_6  37 kB/s |  94 kB     00:02
Last metadata expiration check: 0:00:01 ago on Sun Jan 19 08:42:03 2020.
Dependencies resolved.
================================================================================
 Package          Arch   Version                               Repository  Size
================================================================================
Installing:
 nodejs           x86_64 2:12.14.1-1nodesource                 nodesource  22 M
Installing dependencies:
 python2          x86_64 2.7.16-12.module_el8.1.0+219+cf9e6ac9 AppStream  109 k
 python2-libs     x86_64 2.7.16-12.module_el8.1.0+219+cf9e6ac9 AppStream  6.0 M
 python2-pip-wheel
                  noarch 9.0.3-14.module_el8.1.0+219+cf9e6ac9  AppStream  1.2 M
 python2-setuptools-wheel
                  noarch 39.0.1-11.module_el8.1.0+219+cf9e6ac9 AppStream  289 k
Installing weak dependencies:
 python2-pip      noarch 9.0.3-14.module_el8.1.0+219+cf9e6ac9  AppStream  2.0 M
 python2-setuptools
                  noarch 39.0.1-11.module_el8.1.0+219+cf9e6ac9 AppStream  643 k
Enabling module streams:
 python27                2.7

Transaction Summary
================================================================================
Install  7 Packages

Total download size: 32 M
Installed size: 104 M
Downloading Packages:
(1/7): python2-2.7.16-12.module_el8.1.0+219+cf9 165 kB/s | 109 kB     00:00
(2/7): python2-pip-9.0.3-14.module_el8.1.0+219+ 571 kB/s | 2.0 MB     00:03
(3/7): python2-pip-wheel-9.0.3-14.module_el8.1. 409 kB/s | 1.2 MB     00:02
(4/7): python2-libs-2.7.16-12.module_el8.1.0+21 1.5 MB/s | 6.0 MB     00:03
(5/7): python2-setuptools-39.0.1-11.module_el8. 1.7 MB/s | 643 kB     00:00
(6/7): python2-setuptools-wheel-39.0.1-11.modul 805 kB/s | 289 kB     00:00
(7/7): nodejs-12.14.1-1nodesource.x86_64.rpm    1.7 MB/s |  22 MB     00:12
--------------------------------------------------------------------------------
Total                                           1.8 MB/s |  32 MB     00:17
warning: /var/cache/dnf/AppStream-02e86d1c976ab532/packages/python2-2.7.16-12.module_el8.1.0+219+cf9e6ac9.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 8483c65d: NOKEY
CentOS-8 - AppStream                            1.6 MB/s | 1.6 kB     00:00
Importing GPG key 0x8483C65D:
 Userid     : "CentOS (CentOS Official Signing Key) <security@centos.org>"
 Fingerprint: 99DB 70FA E1D7 CE22 7FB6 4882 05B5 55B3 8483 C65D
 From       : /etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
Key imported successfully
warning: /var/cache/dnf/nodesource-c1a37d2599ffab0c/packages/nodejs-12.14.1-1nodesource.x86_64.rpm: Header V4 RSA/SHA512 Signature, key ID 34fa74dd: NOKEY
Node.js Packages for Enterprise Linux 8 - x86_6 1.6 MB/s | 1.6 kB     00:00
Importing GPG key 0x34FA74DD:
 Userid     : "NodeSource <gpg-rpm@nodesource.com>"
 Fingerprint: 2E55 207A 95D9 944B 0CC9 3261 5DDB E8D4 34FA 74DD
 From       : /etc/pki/rpm-gpg/NODESOURCE-GPG-SIGNING-KEY-EL
Key imported successfully
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                        1/1
  Installing       : python2-setuptools-wheel-39.0.1-11.module_el8.1.0+21   1/7
  Installing       : python2-pip-wheel-9.0.3-14.module_el8.1.0+219+cf9e6a   2/7
  Installing       : python2-libs-2.7.16-12.module_el8.1.0+219+cf9e6ac9.x   3/7
  Installing       : python2-pip-9.0.3-14.module_el8.1.0+219+cf9e6ac9.noa   4/7
  Installing       : python2-setuptools-39.0.1-11.module_el8.1.0+219+cf9e   5/7
  Installing       : python2-2.7.16-12.module_el8.1.0+219+cf9e6ac9.x86_64   6/7
  Running scriptlet: python2-2.7.16-12.module_el8.1.0+219+cf9e6ac9.x86_64   6/7
  Running scriptlet: nodejs-2:12.14.1-1nodesource.x86_64                    7/7
  Installing       : nodejs-2:12.14.1-1nodesource.x86_64                    7/7
  Running scriptlet: nodejs-2:12.14.1-1nodesource.x86_64                    7/7
  Verifying        : python2-2.7.16-12.module_el8.1.0+219+cf9e6ac9.x86_64   1/7
  Verifying        : python2-libs-2.7.16-12.module_el8.1.0+219+cf9e6ac9.x   2/7
  Verifying        : python2-pip-9.0.3-14.module_el8.1.0+219+cf9e6ac9.noa   3/7
  Verifying        : python2-pip-wheel-9.0.3-14.module_el8.1.0+219+cf9e6a   4/7
  Verifying        : python2-setuptools-39.0.1-11.module_el8.1.0+219+cf9e   5/7
  Verifying        : python2-setuptools-wheel-39.0.1-11.module_el8.1.0+21   6/7
  Verifying        : nodejs-2:12.14.1-1nodesource.x86_64                    7/7

Installed:
  nodejs-2:12.14.1-1nodesource.x86_64
  python2-pip-9.0.3-14.module_el8.1.0+219+cf9e6ac9.noarch
  python2-setuptools-39.0.1-11.module_el8.1.0+219+cf9e6ac9.noarch
  python2-2.7.16-12.module_el8.1.0+219+cf9e6ac9.x86_64
  python2-libs-2.7.16-12.module_el8.1.0+219+cf9e6ac9.x86_64
  python2-pip-wheel-9.0.3-14.module_el8.1.0+219+cf9e6ac9.noarch
  python2-setuptools-wheel-39.0.1-11.module_el8.1.0+219+cf9e6ac9.noarch

Complete!
Removing intermediate container a6f52a14bfbc
 ---> 29a93e78f5e2
Step 4/7 : WORKDIR /root/project
 ---> Running in fe701814cbe8
Removing intermediate container fe701814cbe8
 ---> eda559d13b87
Step 5/7 : COPY ./ ./
 ---> da28659ab618
Step 6/7 : RUN cd src  && npm install
 ---> Running in e96081f27d89
npm WARN src@1.0.0 No description
npm WARN src@1.0.0 No repository field.

added 50 packages from 37 contributors and audited 126 packages in 169.473s
found 0 vulnerabilities

Removing intermediate container e96081f27d89
 ---> da2897f4c613
Step 7/7 : EXPOSE 8080:80
 ---> Running in db58b4e3fe1f
Removing intermediate container db58b4e3fe1f
 ---> 1447d55955ca
Successfully built 1447d55955ca
Successfully tagged demo:latest

用命令查看构建过程和中间层镜像

E:\PJ\程序设计\docker容器技术\dome\nodejsDockerfile>docker history demo
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
1447d55955ca        13 minutes ago      /bin/sh -c #(nop)  EXPOSE 8080:80               0B
da2897f4c613        13 minutes ago      /bin/sh -c cd src  && npm install               2.31MB
da28659ab618        16 minutes ago      /bin/sh -c #(nop) COPY dir:51e2c52b32624331c…   15.4kB
eda559d13b87        16 minutes ago      /bin/sh -c #(nop) WORKDIR /root/project         0B
29a93e78f5e2        16 minutes ago      /bin/sh -c curl --silent --location https://…   144MB
6bed20c22168        17 minutes ago      /bin/sh -c #(nop)  LABEL maintainer=wm 15804…   0B
470671670cac        33 hours ago        /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
<missing>           33 hours ago        /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B
<missing>           4 days ago          /bin/sh -c #(nop) ADD file:aa54047c80ba30064…   237MB

Docker容器网络基础

工具安装

$ yum install -y bridge-utils # 网桥管理工具
$ yum install -y net-tools # 安装ifconfig,自行查看自己的linux不是必须的

网桥管理

网桥相当于网络中的交换机(不完全正确,但是可以这么想)。

$ brctl addbr br0 # 新建br0网桥
$ brctl addif br0 eth0 # 让eth0 成为 br0 的一个 interface

ifconfig命令

ifconfig工具不仅可以被用来简单地获取网络接口配置信息,还可以修改这些配置。用ifconfig命令配置的网卡信息,在网卡重启后机器重启后,配置就不存在。要想将上述的配置信息永远的存的电脑里,那就要修改网卡的配置文件了。

$ ifconfig # 查看网卡状态
$ ifconfig eth0 {up|down} # 启动或关闭eth0网卡
$ ifconfig eth0 192.168.1.100 netmask 255.255.255.0 broadcast 192.168.1.255 # 配置eth0的Ip地址,子网地址,广播地址

配置Docker的网桥

$ brctl addbr br0 # 新建br0网桥
$ ifconfig br0 192.168.1.100 netmask 255.255.255.0 # 配置br0的Ip地址,子网地址
$ vi /lib/systemd/system/docker.service 
# 添加docker守护进程的启动参数 -b=br0
# ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -b=br0

$ systemctl daemon-reload && systemctl restart docker

Docker容器间的通信

默认启动参数的—icc=true,所以docker容器间是允许通信的的。

$ docker run -it --link <运行中容器名>:<标识名> <镜像名>
# 运行中的容器名 必须是运行中的容器
# 标识名 是在该容器中调用的名称,他类型于localhost

指定容器间通信

首先配置docker守护进程的启动参数

$ vi /lib/systemd/system/docker.service 
# 添加docker守护进程的启动参数 ---icc=false --iptables=true
# ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --icc=false --iptables=true
# --iptables=true 将策略写入宿主机iptables进行隔离控制

然后使用 --link参数启动

$ docker run -it --link <运行中容器名>:<标识名> <镜像名>
# 运行中的容器名 必须是运行中的容器
# 标识名 是在该容器中调用的名称,他类型于localhost

现在该容器就与<运行中容器名>是连通的。

Docker容器的数据卷(Data Volume)

数据卷是一个特殊的目录,他可以绕开联合文件系统,为多个docker容器提供访问。

作用

  • 存储永久的数据
  • 共享给多个docker的访问空间

特点

  • 数据卷可以在容器直接共享
  • 宿主机可以直接操作数据卷里的数据
  • 数据卷的变化不会影响镜像
  • 数据卷一直存在,即使挂载(加载)数据卷的容器坏掉,也不会影响数据卷

挂载方式

  • volumes:Docker管理宿主机文件系统的一部分,默认位于 /var/lib/docker/volumes 目录
  • bind mounts:意为着可以存储在宿主机系统的任意位置
  • tmpfs:挂载存储在宿主机系统的内存中,而不会写入宿主机的文件系统(不常用)

数据卷的操作

docker volume COMMAND

COMMAND:
  create <数据卷名>    创建数据卷
  inspect <数据卷名>   显示一个或多个卷上的详细信息
  ls                  列出所有的数据卷 包括临时的
  prune               删除没有用的数据卷
  rm <数据卷名>        删除数据卷

基础使用

命令方式挂载数据卷
docker run -it -v <宿主机路径|数据卷名>:<容器内的路径>[:ro] <image>
# -v 挂载数据卷
# ro 只读权限
Dockerfile挂载
FROM centos
VOLUME [ "/data" ]
# 这里的/data是容器内的路径
# 因为没有指定宿主机的位置所以他默认挂载到 
# /var/lib/docker/volumes/xxx/_data
# xxx 是哈希值
共享其他容器的数据卷
docker run -it --volumes-from <容器名称> <image> # 创建容器并且其他容器的数据卷

注意:在不指定宿主机路径时创建的数据卷容器会在删除引用他的容器后系统会自动删除这个临时的数据卷

Docker跨主机连接

Weave通过创建虚拟网络使docker容器能够跨主机通信并能够自动相互发现。

第一步:安装weave

curl -L git.io/weave -o /usr/local/bin/weave  #下载
chmod a+x /usr/local/bin/weave  #赋予执行权限

第二步:启动weave

host1(master):

IP:10.130.0.1/8

weave launch
# 启动weave
eval $(weave env)
# 进入weave环境
# 关闭weave需要执行下面这条
# eval $(weave env --restore) && weave stop
docker run --name masterhost -it centos
# 启动一个容器名为masterhost

host2:

IP:10.130.0.2/8

weave launch 10.130.0.1
# 启动weave,并连接到host1
eval $(weave env)
# 进入weave环境
# 关闭weave需要执行下面这条
# eval $(weave env --restore) && weave stop
docker run --name node1host -it centos
# 启动一个容器名为 node1host

第三步:测试

host1(master)->root@masterhost:

ping node1host
# 通过√

host2->root@node1host:

ping masterhost
# 通过√

注意事项

如果有防火墙$HOST1$HOST2,您必须允许流量通过TCP 6783和UDP 6783/6784,这是WARW的控制和数据端口。

如果想更深入的了解weave,小编推荐大家一篇文章docker: weave 分析和实战这位大神写的文章。

最后

docker的知识点,差不多就是这么多,对于开发岗来说这些就差不多了,如果有运维的朋友,你还得需要去看官方的知识,来学习更多的docker知识。

差不多就这样吧,再次感谢各位花时间可以看鄙人的文章,正好快过年了,提前祝大家新年快乐。如果可以的话可以【点赞】【收藏】【转发】三连一波,鼓励一下。

byby

精彩文章

VM15安装黑苹果10.14.5

Hello,大家好,今天又是一个阳光明媚的上午。今天给大家安利一个硬核教程,在VM15上安装黑苹果10.14.5 mojave。废话不多说咱们开...

GraphQL下一代API标准

GrapthQL介绍 GraphQL是Facebook开发的一种数据查询语言,于2015年发布。 GraphQL是RESTful的升级版 Gra...

DDNS For NodeJs

DDNS For NodeJs GIT仓库 引言 DDNS For NodeJs 是使用nodejs实现的DDNS的工具,通过腾讯云API实现的...

InterfaceMapping内网穿透框架(nodejs)

GIT仓库 项目介绍 基于SocketIo和express的nodejs框架,实现api接口的映射,主要用于通过公网服务器访问内网资源。 类似于...



----------------------------------------------------------------------
# Docker v19.x

> #### 提示
>
> 首先非常感谢你能在闲暇之余点开了我的这篇文章,这篇文章因为是比较全面的Docker入门的一个教程,所以可能需要花费比较长的时间来阅读能比较多,所以如果方便的化你可以点击下面的【赞】或者【收藏】来阅读。最后非常感谢你的阅读,有什么问题可以评论留言,小编会在看到的第一时间给你回复,谢谢。
>
> 环境
>
> - centos7
> - docker19.x

> #### 目录
>
> @[TOC]



## 什么是Docker

简单来说就是将应用程序部署到独立的容器,每个容器相当于一个小的linux系统。通过将容器进行打包成镜像,放到将镜像放到任何有Docker环境的系统上运行。

使用Go语言开发,基于Apache2.0开源协议。

## Docker的优势

- Docker提供简单的轻量的服务器部署。
- 可以清楚的将开发人员与运维人员的职责分离。
- 快速的开发生命周期。
- 面向服务的架构,每个服务相互隔离。

## Docker应用在哪里

- 可以使用Docker容器开发后测试然后部署服务。
- 创建相互隔离的运行环境。
- 搭建测试环境,例如集群测试。

## Docker容器的能力

- 文件系统的隔离
- 进程的隔离
- 网络的隔离
- 硬件资源的隔离和分组

## Docker的核心组成

- Docker Client 客户端
- Docker Daemon 守护进程
- Docker Image 镜像
- Docker Container 容器
- Docker Registry 仓库

### Docker Client与Docker Daemon

Docker是C/S架构的程序,其中Docker Client扮演的是客户端,Docker Daemon扮演的是服务器端。

docker Client即可是在本机也可以在远程。

### Docker Image

镜像好比容器的源代码,保存了容器启动的各种条件。

Docker将一些容器运行的系统与应用服务打包起来,通过联合加载的方式运行,这个打包起来的文件就成为镜像。

一个镜像可以放到另一个镜像的底部,最下面的镜像被称为基础镜像。

### Docker Container

Docker的容器是Dacker的执行单元。

如果说镜像是打包,那么容器就是运行打包好的镜像。

### Docker Registry

Docker仓库是用来保存Docker镜像的地方,分为:

- 公有仓库 Docker Hub
- 私有仓库



## Docker入门操作

### 查看Docker的版本

```bash
$ docker version
$ docker info
```

### 搜索镜像

```bash
$ docker search <镜像名>
```

### 下载镜像

```bash
$ docker pull <用户名>/<镜像名>
```

### 启动容器

```bash
$ docker run <用户名>/<镜像名> [命令]
# 在启动的容器中安装Ping
# docker run <用户名>/<镜像名> apt-get install -y ping
```

### 查看运行的容器

```bash
$ docker ps
```

### 提交容器

```bash
$ docker commit <ID> <新名字>
```

### 查看指定ID的容器信息

```bash
$ docker inspect <ID>
```

### 查看有所有镜像

```bash
$ docker images
```

### 上传镜像到Docker Hub

> 先去https://hub.docker.com/官网申请一个docker hub 帐号

```bash
$ docker login # 登录Docker Hub
$ docker images #查看本地镜像
$ docker tag <镜像名> <用户名/镜像名> #将镜像转让我的账号下
$ docker push <用户名>/<镜像名>
```

## 安装Docker

### ubuntu

#### 第一步、检查是否支持Docker

```bash
$ uname -a
#检查内核版本,必须高于3.10
$ ls -l /sys/class/misc/device-mapper
#检查存储驱动
```

#### 第二步、安装docker

```bash
$ wget -qO- https://get.docker.com/ | sh
```

### Centos7

```bash
sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
# 删除所有的Docker
sudo yum install -y yum-utils \
  device-mapper-persistent-data \
  lvm2
sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
# 使用 Docker 仓库进行安装
sudo yum install -y docker-ce docker-ce-cli containerd.io
# 如果提示您接受 GPG 密钥,请选是。
```

### 配置国内的镜像源

```bash
mkdir -p /etc/docker/
echo '{"registry-mirrors":["http://hub-mirror.c.163.com","https://registry.docker-cn.com"]}' > /etc/docker/daemon.json
systemctl daemon-reload && systemctl restart docker
```

## 容器的基本操作

### 普通容器

#### 启动容器

```bash
$ docker run [<用户名>/]<镜像名>[:tag] [命令]
# 在启动的容器中安装Ping
# docker run <用户名>/<镜像名> apt-get install -y ping
```

#### 启动交会容器

```bash
$ docker run [--name=<名称>] -i -t <镜像全名> /bin/bash
# -i 表示一直保持输入
# -t 表示打开tty终端
# --name 自定义名称
```

#### 查看容器

```bash
$ docker ps [-a][-l]
# -a 查看所有的容器
# -l 查看最新的容器
```

#### 查看指定ID的容器信息

```bash
$ docker inspect <ID>
```

#### 启动/停止容器

```bash
$ docker [-i] start/stop <容器>
# -i表示持续输入
```

#### 删除容器

```bash
$ docker rm <容器>
```

### 守护式容器

#### 特点

- 可以长期运行
- 没有交互会话
- 非常适合运行应用服务

#### 命令

##### 方法一

```bash
$ docker run -i -t <镜像> /bin/bash
# ctrl+p ctrl+q 退出bash,但没关闭容器
$ docker attach <正在运行容器>
# 重新进入正在运行的容器
```

##### 方法二

```bash
$ docker run -d <镜像> <命令>
# -d 后台守护
```

#### 查看容器日志

```bash
$ docker logs [-f][-t][--tail=n] 容器名
# -f 持续输出日志
# -t 日志加上时间戳
# --tail 返回最后的多少行
```

#### 查看运行中的容器的进程

```bash
$ docker top <容器>
```

#### 在运行的容器中启动新的进程

```bash
$ docker exec [-d][-i][-t] <容器名> [命令]
# -d 后台运行
# -i 交会运行
# -t 打开终端
```

#### 停止容器

```bash
$ docker kill/stop <容器名>
# kill 直接停止
# stop 等待进程结束后停止
```

#### 设置端口映射

```bash
$ docker run [-P][-p <port> | <port>:<port>] ...
# -P 映射容器中所有的端口
# -p 指定映射容器中某几个端口
# eg:
$ docker run -P -i -t ubuntu /bin/bash # 映射所有的端口
$ docker run -p 80 -i -t ubuntu /bin/bash # 映射80端口
$ docker run -p 8080:80 -i -t ubuntu /bin/bash # 将内部的80映射为8080
$ docker run -p 127.0.0.1:8080:80 -i -t ubuntu /bin/bash # 将内部的80端口映射为127.0.0.1:8080
# 注意:如果使用5、6行的方法进行映射,外部端口是随机分配的
```



## 管理镜像

### 概念

- TAG:标签
  - 默认:latest
  - 这里多少为版本
  - eg:docker pull node:12.1.1 下载nodejs12.1.1版本

### 基本操作

#### 显示所有的镜像

```bash
$ docker images [-q][-a] [仓库]
# -q 只看id
# -a 查看所有
```

#### 查看镜像的详细

```bash
$ docker inspace <镜像名>
```

#### 删除镜像

```bash
$ docker rmi [-f] <镜像名>
# -f 强制删除
```

#### 查找镜像

方法1:镜像dockerhub上查找

方法2:

```bash
$ docker search [--automated][-no-trunc][-s <num>] <镜像名>
# --automated 只显示自动化选项
# --no-trunc 不分页显示
# -s 显示的最低num的stat镜像
```

#### 下载镜像

```bash
$ docker pull [-a] <镜像名>
# -a 下载匹配的所有镜像
```

#### 标记镜像到某个仓库

```bash
$ docker tag  IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
```

#### 上传镜像到DockerHub

```bash
$ docker images #查看本地镜像
$ docker tag <镜像名> <用户名/镜像名> #将镜像转让我的账号下
$ docker push <用户名/镜像名:Tag> #上传镜像
```



## 打包镜像

> 打包镜像有两种方法,推荐使用Dockerfie方法

### 使用commit打包

将部署好的容器进行打包。

```bash
$ docker commit [-a][-m][-p] <容器> <用户名/镜像名:版本>
# -a "" 镜像作者
# -m "" 打包备注
# -p 不停止镜像打包
```

### 使用Dockerfile文件打包

#### 第一步:创建Dockerfile文件

```dockerfile
#Dockerfile
FORM <基础镜像:Tag>
MAINTAINER <用户名> "联系方式" #新版本推荐使用 LABEL maintainer=value
RUN <linux命令>
...
EXPOSE <端口号>
```

> 说明:
>
> 这个`EXPOSE`指令实际上并不发布端口。它作为构建映像的人和运行容器的人之间的一种文档类型,而这些港口将被发布。若要在运行容器时实际发布端口,请使用`-p`旗上`docker run`若要发布和映射一个或多个端口,或`-P`标志以发布所有公开的端口,并将它们映射到高阶端口。

#### 第二步:执行docker build命令

```bash
$ docker build [-t <镜像名>][--no-cache] <上下文路径>
# -t 镜像名称
# --no-cache 不使用缓存构建
# 上下文路径:
#         docker build 会将这个路径下所有的文件都打包上传给 Docker 引擎,
#         引擎内将这些内容展开后,就能获取到所有指定上下文中的文件了
```

> 注意不要将 `/` 作为上下文路径,因为他会把硬盘上所有的数据发给docker守护进程.

#### .dockerignore

创建`.dockerignore`文件,通过在该文件里添加匹配目录,可以在执行`docker build -t xxx .`命令时不上传匹配的目录。

```dockerfile
#.dockerignore
*/temp* #匹配根目录下的子目录内所有的以temp开头的文件和文件夹
*/*/temp* #匹配根目录下的子目录的子目录内所有的以temp开头的文件和文件夹
**/temp* #匹配所有目录内的以temp开头的文件和文件夹
!my* #在排除文件及文件夹中允许上传my开头的文件及文件夹
```



## Docker远程访问

> Docker的配置文件在Centos7 `/lib/systemd/system/docker.service`
>
> Docker守护进程Linux上配置文件的默认位置是`/etc/docker/daemon.json`或者通过`--config-file`参数可用于指定非默认位置。

### Docker守护进程启动选项

- -H unix:///var/run/docker.sock
- -H tcp://host:port
- -H fd://(默认)

### 配置开始

#### 第一步:配置远程的Docker

```
vi /lib/systemd/system/docker.service
```

修改[Service]->ExecStart

```
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H 0.0.0.0:2375
```

重启Docker

```
systemctl daemon-reload && systemctl restart docker
```

#### 第二步:配置本地的系统环境变量

```bash
# windows
set DOCKER_HOST=tcp://远程ip

# Centos7
export DOCKER_HOST=tcp://远程ip

# 注意:以上配置都是临时的
```

#### 测试

```bash
docker info
# 是否有结果
# 如果想更准确的测试,可以先将远程的Docker守护进程配置一个labels,然后执行命令即可
```

> 提示:
>
> 其实配置远程还有一种方法就是配置docker守护进程的配置文件`daemon.json`通过配置该文件下的`hosts`内的值也可以实现,需要注意的是这两种方法只需要使用其中一种即可。
>
> ```bash
> # docker.service
> # [Service]->ExecStart
> ExecStart=/usr/bin/dockerd  --containerd=/run/containerd/containerd.sock
>
> # daemon.json
> {
>   "hosts":[
>     "0.0.0.0:2375",
>     "unix:///var/run/docker.sock"
>   ]
> }
> ```



## Dockerfile指令

> 关键知识点
>
> - 上下文路径:
>
>   上下文路径 是在使用`docker build`的时候最后一个参数锁指定的路径,通过该路径`docker客户端`会将该路径的下的所有文件都会发送给`docker守护进程`,然后在用户执行`COPY`和`ADD`的时候进行文件复制。如果有不想发送的文件可以向`.dockerignore`中写入匹配忽略路径。
>
> - RUN的执行过程
>
>   ```dockerfile
>   RUN cd /app
>   RUN echo "hello" > world.txt
>   ```
>
>   每一个 `RUN` 都是启动一个容器、执行命令、然后提交存储层文件变更。第一层 `RUN cd /app` 的执行仅仅是当前进程的工作目录变更,一个内存上的变化而已,其结果不会造成任何文件变更。而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更完全没关系,自然不可能继承前一层构建过程中的内存变化。

### FORM

> 这个`FROM`指令初始化新构建阶段,并设置基础镜像以后的指令。因此`Dockerfile`必须有`FROM`指令。Image可以是任何有效的Image它特别容易从[*公共储存库*](https://docs.docker.com/engine/tutorials/dockerrepos/)下载。

```dockerfile
FROM [--platform=<平台>] <image>[:<tag>] [AS <name>]
# --platform 指定平台 如,linux/amd64, linux/arm64,或windows/amd64;默认自动
# image 镜像名称
# tag 类似于版本
# As 起别名
```

### ARG

> ARG是在当前文件中设置变量,通过ARG定义变量可以在该文件内引用。

```dockerfile
ARG VERSION=latest
FROM busybox:${VERSION} # FORM busybox:latest
```

### LABEL

> `LABEL`指令将元数据添加到Image中。一个`LABEL`是键值对。若要在`LABEL`值内使用引号和反斜杠,就像在命令行解析中一样。

```dockerfile
LABEL <key>=<value> <key>=<value> <key>=<value> ...
```

例子:

```dockerfile
LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
          that label-values can span multiple lines."
```

### EXPOST

> `EXPOSE`指令通知Docker容器在运行时侦听指定的网络端口。您可以指定端口是否侦听TCP或UDP,如果未指定协议,则默认为TCP。
>
> 实际上他并无卵用。这里指定的端口仅仅只是作为文档给其他的人看。

```dockerfile
EXPOSE <port> [<port>/<protocol>...]
# port 端口号
# protocol 协议 tcp或udp
```

### ENV

> 设置环境变量,该环境变量类似于linux中export的设置方法,区别在于他是永久的,所以他可以在后续的shell命令里使用该值。

```dockerfile
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
```

例子:

```dockerfile
ENV HI HELLO
RUN echo "${HI}" # Hello
```

### COPY

> 复制指令,从上下文目录中复制文件或者目录到容器里指定路径。

```dockerfile
COPY [--chown=<user>:<group>] <源路径1>...  <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",...  "<目标路径>"]
# [--chown=<user>:<group>] 用户改变复制到容器内文件的拥有者和属组。
# <源路径> 源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则
```

### ADD

>ADD 指令和 COPY 的使用格式一致(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:
>
>- ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
>- ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。

### RUN

> 执行shell命令

```dockerfile
CMD <shell 命令>
CMD ["<可执行文件或命令>","<param1>","<param2>",...]
```

### CMD

> 类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
>
> - CMD 在docker run 时运行。
> - RUN 是在 docker build。
>
> **作用**:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。
>
> **注意**:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。

```dockerfile
CMD <shell 命令>
CMD ["<可执行文件或命令>","<param1>","<param2>",...]
CMD ["<param1>","<param2>",...]  # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
```

### ENTRYPOINT

> 类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
>
> 但是, 如果运行 docker run 时使用了 --entrypoint 选项,此选项的参数可当作要运行的程序覆盖 ENTRYPOINT 指令指定的程序。
>
> **优点**:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。
>
> **注意**:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
>
> 可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。

```dockerfile
ENTRYPOINT ["<executeable>","<param1>","<param2>",...]
```

### WORKDIR

> 指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。
>
> docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。

```dockerfile
WORKDIR <工作目录路径>
```

### USER

> 用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。

```dockerfile
USER <用户名>[:<用户组>]
```

### HEALTHCHECK

> 用于指定某个程序或者指令来监控 docker 容器服务的运行状态。

```dockerfile
HEALTHCHECK [选项] CMD <命令> #设置检查容器健康状况的命令
# HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK [选项] CMD <命令> # CMD 后面跟随的命令使用,可以参考 CMD 的用法。
```

### ONBUILD

> 他不会在本次docker build的时候执行,会在子镜像构建的时候执行后面的<Dockerfile指令>。

```dockerfile
ONBUILD <Dockerfile指令>
```

### MAINTAINER (官方不推荐)

> 这个是将该镜像的维护人的信息写到镜像中,这是一个旧版的写法。

```dockerfile
MAINTAINER <name>

# 代替方案
LABEL maintainer=<name>
```

### SHELL

> 通过该指令可以指定使用的shell解释器。

```dockerfile
SHELL ["<Shell解释器>", "<默认参数>"]
```

### VOLUME

> 定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。
>
> 在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。
>
> 作用:
>
> - 避免重要的数据,因容器重启而丢失,这是非常致命的。
> - 避免容器不断变大。

```dockerfile
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
```



## Dockerfile的构建原理

docker会在执行每条Dockerfile的指令时会对`FROM`引入的基础镜像进行操作。

每操作一步会运行镜像->生成容器->修改容器->提交容器->生成新的镜像->删除容器,然后在新的镜像上继续修改提交,反复如此,最后生成出最终镜像。这些在中间生成的镜像被称为中间层镜像。

我们可以通过`docker history <镜像名>`来看生成镜像的过程。

Dockerfile源文件和上下文目录

```
2020/01/18  11:34                17 .dockerignore
2020/01/18  14:52               277 Dockerfile
2020/01/18  14:45    <DIR>          src
```

```dockerfile
# 生成一个node的docker环境
FROM centos
LABEL maintainer="wm 15804854160@163.com"
RUN curl --silent --location https://rpm.nodesource.com/setup_12.x | bash - \
&& yum -y install nodejs
WORKDIR /root/project
COPY ./ ./
RUN cd src \
&& npm install
EXPOSE 8080:80
```

构建过程

```bash
E:\PJ\程序设计\docker容器技术\dome\nodejsDockerfile>docker build -t demo .
Sending build context to Docker daemon  22.02kB
Step 1/7 : FROM centos
---> 470671670cac
Step 2/7 : LABEL maintainer="wm 15804854160@163.com" #修改镜像
---> Running in 0a9bdf29772d #运行0a9bdf29772d容器
Removing intermediate container 0a9bdf29772d #删除0a9bdf29772d容器
---> 6bed20c22168 #生成新的镜像
Step 3/7 : RUN curl --silent --location https://rpm.nodesource.com/setup_12.x | bash -  && yum -y install nodejs
---> Running in a6f52a14bfbc

## Installing the NodeSource Node.js 12.x repo...


## Inspecting system...

+ rpm -q --whatprovides redhat-release || rpm -q --whatprovides centos-release || rpm -q --whatprovides cloudlinux-release || rpm -q --whatprovides sl-release
+ uname -m

## Confirming "el8-x86_64" is supported...

+ curl -sLf -o /dev/null 'https://rpm.nodesource.com/pub_12.x/el/8/x86_64/nodesource-release-el8-1.noarch.rpm'

## As yum will try to install Node.js from the AppStream repository
instead of the NodeSource repository, the AppStream's version of Node.js has to be disabled.
## Run `sudo yum module enable -y nodejs` to reactivate the AppStream's Node.js repository.

+ yum module disable -y nodejs
CentOS-8 - AppStream                            1.3 MB/s | 5.9 MB     00:04
CentOS-8 - Base                                 190 kB/s | 4.0 MB     00:21
CentOS-8 - Extras                               367  B/s | 2.1 kB     00:05
Dependencies resolved.
================================================================================
Package           Architecture     Version             Repository         Size
================================================================================
Disabling modules:
nodejs

Transaction Summary
================================================================================

Complete!

## Downloading release setup RPM...

+ mktemp
+ curl -sL -o '/tmp/tmp.w4Aojk1oBL' 'https://rpm.nodesource.com/pub_12.x/el/8/x86_64/nodesource-release-el8-1.noarch.rpm'

## Installing release setup RPM...

+ rpm -i --nosignature --force '/tmp/tmp.w4Aojk1oBL'

## Cleaning up...

+ rm -f '/tmp/tmp.w4Aojk1oBL'

## Checking for existing installations...

+ rpm -qa 'node|npm' | grep -v nodesource

## Run `sudo yum install -y nodejs` to install Node.js 12.x and npm.
## You may also need development tools to build native addons:
     sudo yum install gcc-c++ make
## To install the Yarn package manager, run:
     curl -sL https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
     sudo yum install yarn

Node.js Packages for Enterprise Linux 8 - x86_6  37 kB/s |  94 kB     00:02
Last metadata expiration check: 0:00:01 ago on Sun Jan 19 08:42:03 2020.
Dependencies resolved.
================================================================================
Package          Arch   Version                               Repository  Size
================================================================================
Installing:
nodejs           x86_64 2:12.14.1-1nodesource                 nodesource  22 M
Installing dependencies:
python2          x86_64 2.7.16-12.module_el8.1.0+219+cf9e6ac9 AppStream  109 k
python2-libs     x86_64 2.7.16-12.module_el8.1.0+219+cf9e6ac9 AppStream  6.0 M
python2-pip-wheel
                  noarch 9.0.3-14.module_el8.1.0+219+cf9e6ac9  AppStream  1.2 M
python2-setuptools-wheel
                  noarch 39.0.1-11.module_el8.1.0+219+cf9e6ac9 AppStream  289 k
Installing weak dependencies:
python2-pip      noarch 9.0.3-14.module_el8.1.0+219+cf9e6ac9  AppStream  2.0 M
python2-setuptools
                  noarch 39.0.1-11.module_el8.1.0+219+cf9e6ac9 AppStream  643 k
Enabling module streams:
python27                2.7

Transaction Summary
================================================================================
Install  7 Packages

Total download size: 32 M
Installed size: 104 M
Downloading Packages:
(1/7): python2-2.7.16-12.module_el8.1.0+219+cf9 165 kB/s | 109 kB     00:00
(2/7): python2-pip-9.0.3-14.module_el8.1.0+219+ 571 kB/s | 2.0 MB     00:03
(3/7): python2-pip-wheel-9.0.3-14.module_el8.1. 409 kB/s | 1.2 MB     00:02
(4/7): python2-libs-2.7.16-12.module_el8.1.0+21 1.5 MB/s | 6.0 MB     00:03
(5/7): python2-setuptools-39.0.1-11.module_el8. 1.7 MB/s | 643 kB     00:00
(6/7): python2-setuptools-wheel-39.0.1-11.modul 805 kB/s | 289 kB     00:00
(7/7): nodejs-12.14.1-1nodesource.x86_64.rpm    1.7 MB/s |  22 MB     00:12
--------------------------------------------------------------------------------
Total                                           1.8 MB/s |  32 MB     00:17
warning: /var/cache/dnf/AppStream-02e86d1c976ab532/packages/python2-2.7.16-12.module_el8.1.0+219+cf9e6ac9.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 8483c65d: NOKEY
CentOS-8 - AppStream                            1.6 MB/s | 1.6 kB     00:00
Importing GPG key 0x8483C65D:
Userid     : "CentOS (CentOS Official Signing Key) <security@centos.org>"
Fingerprint: 99DB 70FA E1D7 CE22 7FB6 4882 05B5 55B3 8483 C65D
From       : /etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
Key imported successfully
warning: /var/cache/dnf/nodesource-c1a37d2599ffab0c/packages/nodejs-12.14.1-1nodesource.x86_64.rpm: Header V4 RSA/SHA512 Signature, key ID 34fa74dd: NOKEY
Node.js Packages for Enterprise Linux 8 - x86_6 1.6 MB/s | 1.6 kB     00:00
Importing GPG key 0x34FA74DD:
Userid     : "NodeSource <gpg-rpm@nodesource.com>"
Fingerprint: 2E55 207A 95D9 944B 0CC9 3261 5DDB E8D4 34FA 74DD
From       : /etc/pki/rpm-gpg/NODESOURCE-GPG-SIGNING-KEY-EL
Key imported successfully
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                        1/1
  Installing       : python2-setuptools-wheel-39.0.1-11.module_el8.1.0+21   1/7
  Installing       : python2-pip-wheel-9.0.3-14.module_el8.1.0+219+cf9e6a   2/7
  Installing       : python2-libs-2.7.16-12.module_el8.1.0+219+cf9e6ac9.x   3/7
  Installing       : python2-pip-9.0.3-14.module_el8.1.0+219+cf9e6ac9.noa   4/7
  Installing       : python2-setuptools-39.0.1-11.module_el8.1.0+219+cf9e   5/7
  Installing       : python2-2.7.16-12.module_el8.1.0+219+cf9e6ac9.x86_64   6/7
  Running scriptlet: python2-2.7.16-12.module_el8.1.0+219+cf9e6ac9.x86_64   6/7
  Running scriptlet: nodejs-2:12.14.1-1nodesource.x86_64                    7/7
  Installing       : nodejs-2:12.14.1-1nodesource.x86_64                    7/7
  Running scriptlet: nodejs-2:12.14.1-1nodesource.x86_64                    7/7
  Verifying        : python2-2.7.16-12.module_el8.1.0+219+cf9e6ac9.x86_64   1/7
  Verifying        : python2-libs-2.7.16-12.module_el8.1.0+219+cf9e6ac9.x   2/7
  Verifying        : python2-pip-9.0.3-14.module_el8.1.0+219+cf9e6ac9.noa   3/7
  Verifying        : python2-pip-wheel-9.0.3-14.module_el8.1.0+219+cf9e6a   4/7
  Verifying        : python2-setuptools-39.0.1-11.module_el8.1.0+219+cf9e   5/7
  Verifying        : python2-setuptools-wheel-39.0.1-11.module_el8.1.0+21   6/7
  Verifying        : nodejs-2:12.14.1-1nodesource.x86_64                    7/7

Installed:
  nodejs-2:12.14.1-1nodesource.x86_64
  python2-pip-9.0.3-14.module_el8.1.0+219+cf9e6ac9.noarch
  python2-setuptools-39.0.1-11.module_el8.1.0+219+cf9e6ac9.noarch
  python2-2.7.16-12.module_el8.1.0+219+cf9e6ac9.x86_64
  python2-libs-2.7.16-12.module_el8.1.0+219+cf9e6ac9.x86_64
  python2-pip-wheel-9.0.3-14.module_el8.1.0+219+cf9e6ac9.noarch
  python2-setuptools-wheel-39.0.1-11.module_el8.1.0+219+cf9e6ac9.noarch

Complete!
Removing intermediate container a6f52a14bfbc
---> 29a93e78f5e2
Step 4/7 : WORKDIR /root/project
---> Running in fe701814cbe8
Removing intermediate container fe701814cbe8
---> eda559d13b87
Step 5/7 : COPY ./ ./
---> da28659ab618
Step 6/7 : RUN cd src  && npm install
---> Running in e96081f27d89
npm WARN src@1.0.0 No description
npm WARN src@1.0.0 No repository field.

added 50 packages from 37 contributors and audited 126 packages in 169.473s
found 0 vulnerabilities

Removing intermediate container e96081f27d89
---> da2897f4c613
Step 7/7 : EXPOSE 8080:80
---> Running in db58b4e3fe1f
Removing intermediate container db58b4e3fe1f
---> 1447d55955ca
Successfully built 1447d55955ca
Successfully tagged demo:latest
```

用命令查看构建过程和中间层镜像

```
E:\PJ\程序设计\docker容器技术\dome\nodejsDockerfile>docker history demo
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
1447d55955ca        13 minutes ago      /bin/sh -c #(nop)  EXPOSE 8080:80               0B
da2897f4c613        13 minutes ago      /bin/sh -c cd src  && npm install               2.31MB
da28659ab618        16 minutes ago      /bin/sh -c #(nop) COPY dir:51e2c52b32624331c…   15.4kB
eda559d13b87        16 minutes ago      /bin/sh -c #(nop) WORKDIR /root/project         0B
29a93e78f5e2        16 minutes ago      /bin/sh -c curl --silent --location https://…   144MB
6bed20c22168        17 minutes ago      /bin/sh -c #(nop)  LABEL maintainer=wm 15804…   0B
470671670cac        33 hours ago        /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
<missing>           33 hours ago        /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B
<missing>           4 days ago          /bin/sh -c #(nop) ADD file:aa54047c80ba30064…   237MB
```



## Docker容器网络基础

### 工具安装

```bash
$ yum install -y bridge-utils # 网桥管理工具
$ yum install -y net-tools # 安装ifconfig,自行查看自己的linux不是必须的
```

### 网桥管理

> 网桥相当于网络中的交换机(不完全正确,但是可以这么想)。

```bash
$ brctl addbr br0 # 新建br0网桥
$ brctl addif br0 eth0 # 让eth0 成为 br0 的一个 interface
```

### ifconfig命令

> ifconfig工具不仅可以被用来简单地获取网络接口配置信息,还可以修改这些配置。用ifconfig命令配置的网卡信息,在网卡重启后机器重启后,配置就不存在。要想将上述的配置信息永远的存的电脑里,那就要修改网卡的配置文件了。

```bash
$ ifconfig # 查看网卡状态
$ ifconfig eth0 {up|down} # 启动或关闭eth0网卡
$ ifconfig eth0 192.168.1.100 netmask 255.255.255.0 broadcast 192.168.1.255 # 配置eth0的Ip地址,子网地址,广播地址
```

### 配置Docker的网桥

```bash
$ brctl addbr br0 # 新建br0网桥
$ ifconfig br0 192.168.1.100 netmask 255.255.255.0 # 配置br0的Ip地址,子网地址
$ vi /lib/systemd/system/docker.service
# 添加docker守护进程的启动参数 -b=br0
# ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -b=br0

$ systemctl daemon-reload && systemctl restart docker
```



## Docker容器间的通信

> 默认启动参数的`—icc=true`,所以docker容器间是允许通信的的。

```bash
$ docker run -it --link <运行中容器名>:<标识名> <镜像名>
# 运行中的容器名 必须是运行中的容器
# 标识名 是在该容器中调用的名称,他类型于localhost
```

### 指定容器间通信

首先配置docker守护进程的启动参数

```bash
$ vi /lib/systemd/system/docker.service
# 添加docker守护进程的启动参数 ---icc=false --iptables=true
# ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --icc=false --iptables=true
# --iptables=true 将策略写入宿主机iptables进行隔离控制
```

然后使用 --link参数启动

```bash
$ docker run -it --link <运行中容器名>:<标识名> <镜像名>
# 运行中的容器名 必须是运行中的容器
# 标识名 是在该容器中调用的名称,他类型于localhost
```

现在该容器就与<运行中容器名>是连通的。



## Docker容器的数据卷(Data Volume)

> 数据卷是一个特殊的目录,他可以绕开联合文件系统,为多个docker容器提供访问。

### 作用

- 存储永久的数据
- 共享给多个docker的访问空间

### 特点

- 数据卷可以在容器直接共享
- 宿主机可以直接操作数据卷里的数据
- 数据卷的变化不会影响镜像
- 数据卷一直存在,即使挂载(加载)数据卷的容器坏掉,也不会影响数据卷

### 挂载方式

- volumes:Docker管理宿主机文件系统的一部分,默认位于 /var/lib/docker/volumes 目录
- bind mounts:意为着可以存储在宿主机系统的任意位置
- tmpfs:挂载存储在宿主机系统的内存中,而不会写入宿主机的文件系统(不常用)

### 数据卷的操作

```bash
docker volume COMMAND

COMMAND:
  create <数据卷名>    创建数据卷
  inspect <数据卷名>   显示一个或多个卷上的详细信息
  ls                  列出所有的数据卷 包括临时的
  prune                         删除没有用的数据卷
  rm <数据卷名>        删除数据卷
```

### 基础使用

#### 命令方式挂载数据卷

```bash
docker run -it -v <宿主机路径|数据卷名>:<容器内的路径>[:ro] <image>
# -v 挂载数据卷
# ro 只读权限
```

#### Dockerfile挂载

```dockerfile
FROM centos
VOLUME [ "/data" ]
# 这里的/data是容器内的路径
# 因为没有指定宿主机的位置所以他默认挂载到
# /var/lib/docker/volumes/xxx/_data
# xxx 是哈希值
```

#### 共享其他容器的数据卷

```bash
docker run -it --volumes-from <容器名称> <image> # 创建容器并且其他容器的数据卷
```

*注意:在不指定宿主机路径时创建的数据卷容器会在删除引用他的容器后系统会自动删除这个临时的数据卷*



## Docker跨主机连接

> Weave通过创建虚拟网络使docker容器能够跨主机通信并能够自动相互发现。

### 第一步:安装weave

```shell
curl -L git.io/weave -o /usr/local/bin/weave  #下载
chmod a+x /usr/local/bin/weave  #赋予执行权限
```

### 第二步:启动weave

host1(master):

IP:10.130.0.1/8

```shell
weave launch
# 启动weave
eval $(weave env)
# 进入weave环境
# 关闭weave需要执行下面这条
# eval $(weave env --restore) && weave stop
docker run --name masterhost -it centos
# 启动一个容器名为masterhost
```

host2:

IP:10.130.0.2/8

```shell
weave launch 10.130.0.1
# 启动weave,并连接到host1
eval $(weave env)
# 进入weave环境
# 关闭weave需要执行下面这条
# eval $(weave env --restore) && weave stop
docker run --name node1host -it centos
# 启动一个容器名为 node1host
```

### 第三步:测试

host1(master)->root@masterhost:

```shell
ping node1host
# 通过√
```

host2->root@node1host:

```shell
ping masterhost
# 通过√
```

### 注意事项

如果有防火墙`$HOST1`和`$HOST2`,您必须允许流量通过TCP 6783和UDP 6783/6784,这是WARW的控制和数据端口。

如果想更深入的了解weave,小编推荐大家一篇文章[docker: weave 分析和实战](https://blog.csdn.net/bigtree_3721/article/details/101031036)这位大神写的文章。



## 最后

docker的知识点,差不多就是这么多,对于开发岗来说这些就差不多了,如果有运维的朋友,你还得需要去看官方的知识,来学习更多的docker知识。

差不多就这样吧,再次感谢各位花时间可以看鄙人的文章,正好快过年了,提前祝大家新年快乐。如果可以的话可以【点赞】【收藏】【转发】三连一波,鼓励一下。

byby



## 精彩文章

### [VM15安装黑苹果10.14.5](https://www.jianshu.com/p/6b35cd268a09)

> Hello,大家好,今天又是一个阳光明媚的上午。今天给大家安利一个硬核教程,在VM15上安装黑苹果10.14.5 mojave。废话不多说咱们开...

### [GraphQL下一代API标准](https://www.jianshu.com/p/8b3d707b2e1b)

> GrapthQL介绍 GraphQL是Facebook开发的一种数据查询语言,于2015年发布。 GraphQL是RESTful的升级版 Gra...

### [DDNS For NodeJs](https://www.jianshu.com/p/1b7dca3eea23)

> DDNS For NodeJs GIT仓库 引言 DDNS For NodeJs 是使用nodejs实现的DDNS的工具,通过腾讯云API实现的...

### [InterfaceMapping内网穿透框架(nodejs)](https://www.jianshu.com/p/072bcd16a617)

> GIT仓库 项目介绍 基于SocketIo和express的nodejs框架,实现api接口的映射,主要用于通过公网服务器访问内网资源。 类似于...

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Hmily 发表于 2020-5-9 11:13
明显不行。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 12:40

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表