Docker 安装、镜像、dockerfile、容器、仓库

2018-05-30

 

 参考:

1、《docker从入门到实战》

2、菜鸟教程http://www.runoob.com/docker/docker-command-manual.html、

3、docker官网https://docs.docker.com/install/linux/docker-ce/centos/#uninstall-old-versions

 

1、部署docker

1、卸载旧版本docker
$ sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-selinux \
                  docker-engine-selinux \
                  docker-engine
2、安装依赖包
$ sudo yum install -y yum-utils \
           device-mapper-persistent-data \
           lvm2
3、添加国内 yum 软件源
$ sudo yum-config-manager \
    --add-repo \
    https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo

4、更新 yum 软件源缓存,并安装 docker-ce 。
$ sudo yum makecache fast
$ sudo yum install docker-ce
5、启动 Docker CE:
$ sudo systemctl enable docker
$ sudo systemctl start docker
6、添加用户到docker组,且注消、重新登录。docker安装完毕后会自动创建docker群组、自动设置docker组执行docker相关命令。
$ sudo usermod -aG docker $USER

或者$ sudo gpasswd -a $USER docker

重新登录后验证当前用户已经添加上docker群组:

$ id

另:退出docker群组的命令(不需要执行):gpasswd -d $USER docker

7、测试 Docker 是否安装正确
$ docker run hello-world

报错:Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.37/images/json: dial unix /var/run/docker.sock: connect: permission denied。

  • 原因:没有x执行权限导致。
  • 解决步骤:
    • a、只添加用户到docker组。
    • b、注消、重新登录。

8、配置国内镜像进行加速

新增/etc/docker/daemon.json文件且添加如下内容:

 {

   "registry-mirrors": [

     "https://registry.docker-cn.com"

   ]

 }

重启服务:

$ sudo systemctl daemon-reload

$ sudo systemctl restart docker

检查加速器是否生效:

$ docker info

如果从结果中看到了如下内容,说明配置成功

 Registry Mirrors:

 https://registry.docker-cn.com/

9、添加内核配置参数

默认配置下,如果在 CentOS 使用Docker CE 看到下面的这些警告信息:

WARNING: bridge-nf-call-iptables is disabled

WARNING: bridge-nf-call-ip6tables is disabled

请添加内核配置参数以启用这些功能:

$ sudo tee -a /etc/sysctl.conf <<-EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF

重新加载 sysctl.conf 即可:
$ sudo sysctl -p

10、docker卸载

$ sudo yum remove docker-ce
$ sudo rm -rf /var/lib/docker

 

2安装指定版本

1、卸载旧版本docker
$ sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-selinux \
                  docker-engine-selinux \
                  docker-engine
2、安装 docker-latest

$ yum list | grep docker |grep "1."
$ sudo yum install docker-latest.x86_64
5、启动 Docker CE:
$ sudo systemctl enable docker-latest
$ sudo systemctl start docker-latest
3、注消、重新登录。docker安装完毕后会自动创建docker群组、自动设置docker群组执行docker相关命令。

另:退出docker群组的命令(不需要执行):gpasswd -d $USER docker

 

3、Docker镜像命令

1、docker search :从Docker Hub查找镜像
语法

  • docker search [OPTIONS] TERM

OPTIONS说明:

  • --automated :只列出 automated build类型的镜像;
  • --no-trunc :显示完整的镜像描述;
  • -s :列出收藏数不小于指定值的镜像。

2、docker pull : 从镜像仓库中拉取或者更新指定镜像
语法

  • docker pull [OPTIONS] NAME[:TAG|@DIGEST]

OPTIONS说明:

  • -a :拉取所有 tagged 镜像
  • --disable-content-trust :忽略镜像的校验,默认开启

从私有仓库抓取镜像:docker pull /

3、docker push : 将本地的镜像上传到镜像仓库,要先登陆到镜像仓库
语法

  • docker push [OPTIONS] NAME[:TAG]

OPTIONS说明:

  • --disable-content-trust :忽略镜像的校验,默认开启

4、docker commit :从容器创建一个新的镜像。
语法

  • docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

OPTIONS说明:

  • -a :提交的镜像作者;
  • -c :使用Dockerfile指令来创建镜像;
  • -m :提交时的说明文字;
  • -p :在commit时,将容器暂停。

5、docker images : 列出本地镜像。
语法

  • docker images [OPTIONS] [REPOSITORY[:TAG]]

OPTIONS说明:

  • -a :列出本地所有的镜像(含中间映像层,默认情况下,过滤掉中间映像层);
  • --digests :显示镜像的摘要信息;
  • -f :显示满足条件的镜像;
  • --format :指定返回值的模板文件;
  • --no-trunc :显示完整的镜像信息;
  • -q :只显示镜像ID。

docker images -f dangling=true            显示虚悬镜像
docker images prune                 删除虚拟镜像
docker images --format "{{.ID}}: {{.Repository}}"        直接列出镜像结果,并且只包含镜像ID和仓库名
docker images --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}"        打算以表格等距显示,并且有标题行,和默认一样,不过自己定义列

6、docker diff : 检查容器里文件结构的更改。
语法

  • docker diff [OPTIONS] CONTAINER

7、docker rmi : 删除本地一个或多少镜像。
语法

  • docker rmi [OPTIONS] IMAGE [IMAGE...]

OPTIONS说明:

  • -f :强制删除;
  • --no-prune :不移除该镜像的过程镜像,默认移除;

8、docker save : 将指定镜像保存成 tar 归档文件。
语法

  • docker save [OPTIONS] IMAGE [IMAGE...]

OPTIONS说明:

  • -o :输出到的文件。

9、docker load : 从.tar压缩文件中加载镜像

语法

  • docker load [ -i name.tar]

10、docker export :将文件系统作为一个tar归档文件导出到STDOUT。
语法

  • docker export [OPTIONS] CONTAINER

OPTIONS说明:

  • -o :将输入内容写到文件。

 

11、docker import : 从归档文件中创建镜像。
语法

  • docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]

OPTIONS说明:

    • -c :应用docker 指令创建镜像;
    • -m :提交时的说明文字;

12、tag : 标记镜像
语法

  • docker tag IMAGE[:TAG] [REGISTRY_HOST[:REGISTRY_PORT]/]REPOSITORY[:TAG]

实例:使用docker tag将ubuntu:latest这个镜像标记为127.0.0.1:5000/ubuntu:latest。
$ docker tag ubuntu:latest 127.0.0.1:5000/ubuntu:latest

13、docker history:查看镜像内的历史记录

4、Dockerfile

FROM 指定基础镜像

所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。就像我们之前运行了一个nginx镜像的容器,再进行修改一样,基础镜像是必须指定的。而FROM就是指定基础镜像,因此一个DockerfileFROM是必备的指令,并且必须是第一条指令。

Docker Store上有非常多的高质量的官方镜像,有可以直接拿来使用的服务类的镜像,nginxredismongomysqlhttpdphptomcat;也有一些方便开发、构建、运行各种语言应用的镜像,nodeopenjdkpythonrubygolang等。可以在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。

如果没有找到对应服务的镜像,官方镜像中还提供了一些更为基础的操作系统镜像,ubuntudebiancentosfedoraalpine,这些操作系统的软件库为我们提供了更广阔的扩展空间。

除了选择现有镜像为基础镜像外,Docker还存在一个特殊的镜像,名为scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。

FROM scratch

...

如果你以scratch为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。

不以任何系统为基础,直接将可执行文件复制进镜像的做法并不罕见,比如swarmcoreos/etcd。对于Linux下静态编译的程序来说,并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接FROM scratch会让镜像体积更加小巧。使用Go语言开发的应用很多会使用这种方式来制作镜像,这也是为什么有人认为Go是特别适合容器微服务架构的语言的原因之一。

RUN 执行命令行命令

RUN 多条的写法是完全没有意义的,很多运行时不需要的东西都被装进了镜像里,比如编译环境、更新的软件包等等。结果就是产生非常臃肿、非常多层的镜像,不仅仅增加了构建部署的时间,也很容易出错。这是很多初学Docker的人常犯的一个错误。

Union FS是有最大层数限制的,比如AUFS,曾经是最大不得超过42,现在是不得超过127层。

首先,之前所有的命令只有一个目的,就是编译、安装redis可执行文件。因此没有必要建立很多层,这只是一层的事情。因此,这里没有使用很多个RUN对一一对应不同的命令,而是仅仅使用一个RUN指令,并使用&&将各个所需命令串联起来。将之前的7,简化为了1层。在撰写Dockerfile的时候,要经常提醒自己,这并不是在写Shell脚本,而是在定义每一层该如何构建。

并且,这里为了格式化还进行了换行。Dockerfile支持Shell类的行尾添加\的命令换行方式,以及行首#进行注释的格式。良好的格式,比如换行、缩进、注释等,会让维护、排障更为容易,这是一个比较好的习惯。

此外,还可以看到这一组命令的最后添加了清理工作的命令,删除了为了编译构建所需要的软件,清理了所有下载、展开的文件,并且还清理了apt缓存文件。这是很重要的一步,我们之前说过,镜像是多层存储,每一层的东西并不会在下一层被删除,会一直跟随着镜像。因此镜像构建时,一定要确保每一层只添加真正需要添加的东西,任何无关的东西都应该清理掉,就是每一层构建的最后一定要清理掉无关文件。

COPY 复制文件

格式:

COPY <源路径>... <目标路径

COPY ["<源路径1>",... "<目标路径>"] 

和 RUN 指令一样,也有两种格式,一种类似于命令行,一种类似于函数调用。COPY 指令将从构建上下文目录中 <源路径的文件/目录复制到新的一层的镜像内的 <目标路径位置。比如:

COPY package.json /usr/src/app/

 

<源路径> 可以是多个,甚至可以是通配符,其通配符规则要满足 Go 的 filepath.Match 规则,:

COPY hom* /mydir/

COPY hom?.txt /mydir/

<目标路径> 可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用 WORKDIR 指令来指定)。目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。

此外,还需要注意一点,使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。这个特性对于镜像定制很有用。特别是构建相关文件都在使用 Git进行管理的时候。

 

ADD 更高级的复制文件

ADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。

如果 <源路径是一个 URL,这种情况下,Docker 引擎会试图去下载这个链接的文件放到 <目标路径去。下载后的文件权限自动设置为 600,如果这并不是想要的权限,那么还需要增加额外的一层 RUN 进行权限调整;另外,如果下载的是个压缩包,需要解压缩,也一样还需要额外的一层 RUN 指令进行解压缩。所以不如直接使用 RUN 指令,然后使用 wget 或者 curl 工具下载,处理权限、解压缩、然后清理无用文件更合理。因此,这个功能其实并不实用,而且不推荐使用。

如果 <源路径为一个 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,ADD 指令将会自动解压缩这个压缩文件到 <目标路径去。

在某些情况下,这个自动解压缩的功能非常有用,比如官方镜像 ubuntu :

FROM scratch

ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /

...

但在某些情况下,如果我们真的是希望复制个压缩文件进去,而不解压缩,这时就不可以使用 ADD 命令了。

在 Docker 官方的 Dockerfile 最佳实践文档 中要求,尽可能的使用 COPY,因为 COPY 的语义很明确,就是复制文件而已,而 ADD 则包含了更复杂的功能,其行为也不一定很清晰。最适合使用 ADD 的场合,就是所提及的需要自动解压缩的场合。

另外需要注意的是,ADD 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。

因此在 COPY 和 ADD 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用COPY指令,仅在需要自动解压缩的场合使用ADD

 

CMD 容器启动命令

也是两种格式:

l shell格式:CMD <命令>

l exec格式:CMD ["可执行文件", "参数1", "参数2"...]

l 参数列表格式:CMD ["参数1", "参数2"...]。在指定了ENTRYPOINT指令后,CMD指定具体的参数。

之前介绍容器的时候曾经说过,Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。CMD指令就是用于指定默认的容器主进程的启动命令的。

在运行时可以指定新的命令来替代镜像设置中的这个默认命令,比如,ubuntu镜像默认的CMD/bin/bash,如果我们直接docker run -it ubuntu的话,会直接进入bash。我们也可以在运行时指定运行别的命令,docker run -it ubuntu cat /etc/os-release。这就是用cat /etc/os-release命令替换了默认的/bin/bash命令了,输出了系统版本信息。

在指令格式上,一般推荐使用exec格式,这类格式在解析时会被解析为 JSON 数组,因此一定要使用双引号",而不要使用单引号。

如果使用shell格式的话,实际的命令会被包装为sh -c的参数的形式进行执行。比如:

CMD echo $HOME

在实际执行中,会将其变更为:

CMD [ "sh", "-c", "echo $HOME" ]

这就是为什么我们可以使用环境变量的原因,因为这些环境变量会被 shell 进行解析处理。提到CMD就不得不提容器中应用在前台执行和后台执行的问题。这是初学者常出现的一个混淆。

Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样,用 upstart/systemd 去启动后台服务,容器内没有后台服务的概念。

一些初学者将CMD写为:

CMD service nginx start

然后发现容器执行后就立即退出了。甚至在容器内去使用 systemctl 命令结果却发现根本执行不了。这就是因为没有搞明白前台、后台的概念,没有区分容器和虚拟机的差异,依旧在以传统虚拟机的角度去理解容器。

对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。

而使用 service nginx start 命令,则是希望 upstart 来以后台守护进程形式启动 nginx 服务。而刚才说了 CMD service nginx start 会被理解为 CMD [ "sh", "-c", "service nginx start"] ,因此主进程实际上是 sh 。那么当 service nginx start 命令结束后, sh 也就结束了, sh 作为主进程退出了,自然就会令容器退出。

正确的做法是直接执行 nginx 可执行文件,并且要求以前台形式运行。比如:

CMD ["nginx", "-g", "daemon off;"]

 

ENTRYPOINT 入口点

ENTRYPOINT 的格式和 RUN 指令格式一样,分为 exec 格式和 shell 格式。

ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数。 ENTRYPOINT 在运行时也可以替代,不过比 CMD 要略显繁琐,需要通过 docker run 的参数 --entrypoint 来指定。

当指定了 ENTRYPOINT , CMD 的含义就发生了改变,不再是直接的运行其命令,而是将CMD 的内容作为参数传给 ENTRYPOINT 指令,换句话说实际执行时,将变为:

 ""

那么有了 CMD ,为什么还要有 ENTRYPOINT ?这种  "有什么好处么?让我们来看几个场景。

 

场景一:让镜像变成像命令一样使用

假设我们需要一个得知自己当前公网 IP 的镜像,那么可以先用 CMD 来实现:

FROM ubuntu:16.04

RUN apt-get update \

 && apt-get install -y curl \

 && rm -rf /var/lib/apt/lists/*

CMD [ "curl", "-s", "http://ip.cn" ]

假如我们使用 docker build -t myip . 来构建镜像的话,如果我们需要查询当前公网 IP,只需要执行:

$ docker run myip

当前 IP:61.148.226.66 来自:北京市 联通

,这么看起来好像可以直接把镜像当做命令使用了,不过命令总有参数,如果我们希望加参数呢?比如从上面的 CMD 中可以看到实质的命令是 curl ,那么如果我们希望显示 HTTP头信息,就需要加上 -i 参数。那么我们可以直接加 -i 参数给 docker run myip ?

$ docker run myip -i

docker: Error response from daemon: invalid header field value "oci runtime error: container_linux.go:247: starting container process caused \"exec: \\\"-i\\\": executable file not found in $PATH\"\n".

我们可以看到可执行文件找不到的报错, executable file not found 。之前我们说过,跟在镜像名后面的是 command ,运行时会替换 CMD 的默认值。因此这里的 -i 替换了原来的CMD ,而不是添加在原来的 curl -s http://ip.cn 后面。而 -i 根本不是命令,所以自然找不到。

那么如果我们希望加入 -i 这参数,我们就必须重新完整的输入这个命令:

$ docker run myip curl -s http://ip.cn -i

这显然不是很好的解决方案,而使用 ENTRYPOINT 就可以解决这个问题。现在我们重新用ENTRYPOINT 来实现这个镜像:

FROM ubuntu:16.04

RUN apt-get update \

 && apt-get install -y curl \

 && rm -rf /var/lib/apt/lists/*

ENTRYPOINT [ "curl", "-s", "http://ip.cn" ]

这次我们再来尝试直接使用 docker run myip -i :

$ docker run myip

当前 IP:61.148.226.66 来自:北京市 联通

$ docker run myip -i

HTTP/1.1 200 OK

Server: nginx/1.8.0

Date: Tue, 22 Nov 2016 05:12:40 GMT

Content-Type: text/html; charset=UTF-8

Vary: Accept-Encoding

X-Powered-By: PHP/5.6.24-1~dotdeb+7.1

X-Cache: MISS from cache-2

X-Cache-Lookup: MISS from cache-2:80

X-Cache: MISS from proxy-2_6

Transfer-Encoding: chunked

Via: 1.1 cache-2:80, 1.1 proxy-2_6:8006

Connection: keep-alive

当前 IP:61.148.226.66 来自:北京市 联通

可以看到,这次成功了。这是因为当存在 ENTRYPOINT , CMD 的内容将会作为参数传给ENTRYPOINT ,而这里 -i 就是新的 CMD ,因此会作为参数传给 curl ,从而达到了我们预期的效果。

场景二:应用运行前的准备工作

启动容器就是启动主进程,但有些时候,启动主进程前,需要一些准备工作。

比如 mysql 类的数据库,可能需要一些数据库配置、初始化的工作,这些工作要在最终的mysql 服务器运行之前解决。

此外,可能希望避免使用 root 用户去启动服务,从而提高安全性,而在启动服务前还需要以 root 身份执行一些必要的准备工作,最后切换到服务用户身份启动服务。或者除了服务外,其它命令依旧可以使用 root 身份执行,方便调试等。

这些准备工作是和容器 CMD 无关的,无论 CMD 为什么,都需要事先进行一个预处理的工作。这种情况下,可以写一个脚本,然后放入 ENTRYPOINT 中去执行,而这个脚本会将接到的参数(也就是  )作为命令,在脚本最后执行。比如官方镜像 redis 中就是这么做的:

FROM alpine:3.4

...

RUN addgroup -S redis && adduser -S -G redis redis

...

ENTRYPOINT ["docker-entrypoint.sh"]

EXPOSE 6379

CMD [ "redis-server" ]

可以看到其中为了 redis 服务创建了 redis 用户,并在最后指定了 ENTRYPOINT 为 docker-

entrypoint.sh 脚本。

#!/bin/sh

...

# allow the container to be started with `--user`

if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then

 chown -R redis .

 exec su-exec redis "$0" "$@"

fi

exec "$@"

该脚本的内容就是根据 CMD 的内容来判断,如果是 redis-server 的话,则切换到redis用户身份启动服务器,否则依旧使用 root 身份执行。比如:

$ docker run -it redis id

uid=0(root) gid=0(root) groups=0(root)

ENV 设置环境变量

格式有两种:

 ENV   

 ENV = =... 

这个指令很简单,就是设置环境变量而已,无论是后面的其它指令,如 RUN ,还是运行时的应用,都可以直接使用这里定义的环境变量。

ENV VERSION=1.0 DEBUG=on \

 NAME="Happy Feet"

这个例子中演示了如何换行,以及对含有空格的值用双引号括起来的办法,这和 Shell 下的行为是一致的。

定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。比如在官方 node 镜像Dockerfile ,就有类似这样的代码:

ENV NODE_VERSION 7.2.0

RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.ta

r.xz" \

 && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \

 && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \

 && grep " node-v$NODE_VERSION-linux-x64.tar.xz\$" SHASUMS256.txt | sha256sum -c - \

 && tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=

1 \

 && rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \

 && ln -s /usr/local/bin/node /usr/local/bin/nodejs

在这里先定义了环境变量 NODE_VERSION ,其后的 RUN 这层里,多次使用 $NODE_VERSION 来进行操作定制。可以看到,将来升级镜像构建版本的时候,只需要更新 7.2.0 即可, Dockerfile 构建维护变得更轻松了。

下列指令可以支持环境变量展开:

 ADD 、 COPY 、 ENV 、 EXPOSE 、 LABEL 、 USER 、 WORKDIR 、 VOLUME 、 STOPSIGNAL 、 ONBUILD 

可以从这个指令列表里感觉到,环境变量可以使用的地方很多,很强大。通过环境变量,我们可以让一份 Dockerfile 制作更多的镜像,只需使用不同的环境变量即可。

ARG 构建参数

格式: ARG <参数名>[=<默认值>] 

构建参数和 ENV 的效果一样,都是设置环境变量。所不同的是, ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 ARG 保存密码之类的信息,因为 docker history 还是可以看到所有值的。

Dockerfile 中的 ARG 指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令

 docker build 中用 --build-arg <参数名>=<来覆盖。

在 1.13 之前的版本,要求 --build-arg 中的参数名,必须在 Dockerfile 中用 ARG 定义过了,换句话说,就是 --build-arg 指定的参数,必须在 Dockerfile 中使用了。如果对应参数没有被使用,则会报错退出构建。从 1.13 开始,这种严格的限制被放开,不再报错退出,而是显示警告信息,并继续构建。这对于使用 CI 系统,用同样的构建流程构建不同的Dockerfile 的时候比较有帮助,避免构建命令必须根据每个 Dockerfile 的内容修改。

VOLUME 定义匿名卷

格式为:

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

 VOLUME <路径

之前我们说过,容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume),后面的章节我们会进一步介绍

Docker 卷的概念。为了防止运行时用户忘记将动态文件所保存目录挂载为卷,Dockerfile ,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂

,其应用也可以正常运行,不会向容器存储层写入大量数据。

VOLUME /data

这里的 /data 目录就会在运行时自动挂载为匿名卷,任何向 /data 中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化。当然,运行时可以覆盖这个挂载设置。比如:

docker run -d -v mydata:/data xxxx

在这行命令中,就使用了 mydata 这个命名卷挂载到了 /data 这个位置,替代了Dockerfile 中定义的匿名卷的挂载配置。

EXPOSE 声明端口

格式为 EXPOSE <端口1> [<端口2>...]

EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P ,会自动随机映射 EXPOSE 的端口。

此外,在早期 Docker 版本中还有一个特殊的用处。以前所有容器都运行于默认桥接网络中,因此所有容器互相之间都可以直接访问,这样存在一定的安全性问题。于是有了一个 Docker引擎参数 --icc=false,当指定该参数后,容器间将默认无法互访,除非互相间使用了 --links 参数的容器才可以互通,并且只有镜像中 EXPOSE 所声明的端口才可以被访问。这个 --icc=false 的用法,在引入了 docker network 后已经基本不用了,通过自定义网络可以很轻松的实现容器间的互联与隔离。

要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口区分开来。-p,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。

WORKDIR 指定工作目录

格式为 WORKDIR <工作目录路径>

使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。

之前提到一些初学者常犯的错误是把 Dockerfile 等同于 Shell 脚本来书写,这种错误的理解还可能会导致出现下面这样的错误:

RUN cd /app

RUN echo "hello" > world.txt

如果将这个 Dockerfile 进行构建镜像运行后,会发现找不到 /app/world.txt 文件,或者其内容不是 hello。原因其实很简单,在 Shell ,连续两行是同一个进程执行环境,因此前一个命令修改的内存状态,会直接影响后一个命令;而在 Dockerfile ,这两行 RUN 命令的执行环境根本不同,是两个完全不同的容器。这就是对 Dockerfile 构建分层存储的概念不了解所导致的错误。

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

因此如果需要改变以后各层的工作目录的位置,那么应该使用 WORKDIR 指令。

USER 指定当前用户

格式:USER <用户名

USER 指令和 WORKDIR 相似,都是改变环境状态并影响以后的层。WORKDIR 是改变工作目录,USER 则是改变之后层的执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份。

当然,和 WORKDIR 一样,USER 只是帮助你切换到指定用户而已,这个用户必须是事先建立好的,否则无法切换。

RUN groupadd -r redis && useradd -r -g redis redis

USER redis

RUN [ "redis-server" ]

如果以 root 执行的脚本,在执行期间希望改变身份,比如希望以某个已经建立好的用户来运行某个服务进程,不要使用 su 或者 sudo,这些都需要比较麻烦的配置,而且在 TTY 缺失的环境下经常出错。建议使用 gosu

建立 redis 用户,并使用 gosu 换另一个用户执行命令

RUN groupadd -r redis && useradd -r -g redis redis

下载 gosu

RUN wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.7/

gosu-amd64" \

&& chmod +x /usr/local/bin/gosu \

&& gosu nobody true

设置 CMD,并以另外的用户执行

CMD [ "exec", "gosu", "redis", "redis-server" ]

HEALTHCHECK 健康检查

格式:

 HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令

 HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK 指令是告诉 Docker 应该如何进行判断容器的状态是否正常,这是 Docker 1.12引入的新指令。

在没有 HEALTHCHECK 指令前,Docker 引擎只可以通过容器内主进程是否退出来判断容器是否状态异常。很多情况下这没问题,但是如果程序进入死锁状态,或者死循环状态,应用进程并不退出,但是该容器已经无法提供服务了。在 1.12 以前,Docker 不会检测到容器的这种状态,从而不会重新调度,导致可能会有部分容器已经无法提供服务了却还在接受用户请求。

而自 1.12 之后,Docker 提供了 HEALTHCHECK 指令,通过该指令指定一行命令,用这行命令来判断容器主进程的服务状态是否还正常,从而比较真实的反应容器实际状态。

当在一个镜像指定了 HEALTHCHECK 指令后,用其启动容器,初始状态会为 starting,在 HEALTHCHECK 指令检查成功后变为 healthy,如果连续一定次数失败,则会变为 unhealthy

HEALTHCHECK 支持下列选项:

l  --interval=<间隔>:两次健康检查的间隔,默认为 30 ;

l  --timeout=<时长>:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 ;

l  --retries=<次数>:当连续失败指定次数后,则将容器状态视为 unhealthy,默认 3次。

和 CMD, ENTRYPOINT 一样,HEALTHCHECK 只可以出现一次,如果写了多个,只有最后一个生效。

在 HEALTHCHECK [选项] CMD 后面的命令,格式和 ENTRYPOINT 一样,分为 shell 格式,exec 格式。命令的返回值决定了该次健康检查的成功与否:0:成功;1:失败;2:保留,不要使用这个值。

假设我们有个镜像是个最简单的 Web 服务,我们希望增加健康检查来判断其 Web 服务是否在正常工作,我们可以用 curl 来帮助判断,其 Dockerfile 的 HEALTHCHECK 可以这么写:

FROM nginx

RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*

HEALTHCHECK --interval=5s --timeout=3s \

CMD curl -fs http://localhost/ || exit 1

这里我们设置了每 秒检查一次(这里为了试验所以间隔非常短,实际应该相对较长),如果健康检查命令超过 秒没响应就视为失败,并且使用 curl -fs http://localhost/ || exit1 作为健康检查命令。

使用 docker build 来构建这个镜像:

$ docker build -t myweb:v1 .

构建好了后,我们启动一个容器:

$ docker run -d --name web -p 80:80 myweb:v1

当运行该镜像后,可以通过 docker ps 看到最初的状态为 (health: starting):

$ docker ps

CONTAINER IDIMAGE COMMANDCREATED S

TATUSPORTS NAMES

03e28eb00bd0myweb:v1"nginx -g 'daemon off" 3 seconds ago U

p 2 seconds (health: starting) 80/tcp, 443/tcp web

在等待几秒钟后,再次 docker ps,就会看到健康状态变化为了 (healthy):

$ docker ps

CONTAINER IDIMAGE COMMANDCREATED S

TATUSPORTS NAMES

03e28eb00bd0myweb:v1"nginx -g 'daemon off" 18 seconds agoU

p 16 seconds (healthy) 80/tcp, 443/tcp web

如果健康检查连续失败超过了重试次数,状态就会变为 (unhealthy)

为了帮助排障,健康检查命令的输出(包括 stdout 以及 stderr)都会被存储于健康状态里,可以用 docker inspect 来查看。

$ docker inspect --format '{{json .State.Health}}' web | python -m json.tool

{

"FailingStreak": 0,

"Log": [

{

"End": "2016-11-25T14:35:37.940957051Z",

"ExitCode": 0,

"Output": "\n\n\nWelcome to nginx!</titl</p> <p>e>\n<style>\nbody {\nwidth: 35em;\nmargin: 0 auto;\nfont-f</p> <p>amily: Tahoma, Verdana, Arial, sans-serif;\n}\n</style>\n</head>\n<body>\n<h1>Welc</p> <p>ome to nginx!</h1>\n<p>If you see this page, the nginx web server is successfully inst</p> <p>alled and\nworking. Further configuration is required.</p>\n\n<p>For online documentat</p> <p>ion and support please refer to\n<a href=\"http://nginx.org/\">nginx.org</a>.<br/>\nCo</p> <p>mmercial support is available at\n<a href=\"http://nginx.com/\">nginx.com</a>.</p>\n\n</p> <p><p><em>Thank you for using nginx.</em></p>\n</body>\n</html>\n",</p> <p>"Start": "2016-11-25T14:35:37.780192565Z"</p> <p>}</p> <p>],</p> <p>"Status": "healthy"</p> <p>}</p> <h2><strong>ONBUILD <span style="font-family:'方正黑体_GBK';">为他人做嫁衣裳</span></strong></h2> <p>格式<span style="font-family:Calibri;">:ONBUILD <</span><span style="font-family:'宋体';">其它指令</span><span style="font-family:Calibri;">></span><span style="font-family:'宋体';">。</span></p> <p>ONBUILD <span style="font-family:'宋体';">是一个特殊的指令</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">它后面跟的是其它指令</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">比如 </span><span style="font-family:Calibri;">RUN, COPY </span><span style="font-family:'宋体';">等</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">而这些指令</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">去构建下一级镜像的时候才会被执行。</span></p> <p>Dockerfile <span style="font-family:'宋体';">中的其它指令都是为了定制当前镜像而准备的</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">唯有 </span><span style="font-family:Calibri;">ONBUILD </span><span style="font-family:'宋体';">是为了帮助别人定制自己而准备的。</span></p> <p>假设我们要制作 <span style="font-family:Calibri;">Node.js </span><span style="font-family:'宋体';">所写的应用的镜像。我们都知道 </span><span style="font-family:Calibri;">Node.js </span><span style="font-family:'宋体';">使用 </span><span style="font-family:Calibri;">npm </span><span style="font-family:'宋体';">进行包管理</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">所有依赖、配置、启动信息等会放到 </span><span style="font-family:Calibri;">package.json </span><span style="font-family:'宋体';">文件里。在拿到程序代码后</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">需要先进行</span><span style="font-family:Calibri;">npm install </span><span style="font-family:'宋体';">才可以获得所有需要的依赖。然后就可以通过 </span><span style="font-family:Calibri;">npm start </span><span style="font-family:'宋体';">来启动应用。因此</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">一般来说会这样写 </span><span style="font-family:Calibri;">Dockerfile:</span></p> <p>FROM node:slim</p> <p>RUN mkdir /app</p> <p>WORKDIR /app</p> <p>COPY ./package.json /app</p> <p>RUN [ "npm", "install" ]</p> <p>COPY . /app/</p> <p>CMD [ "npm", "start" ]</p> <p>把这个 <span style="font-family:Calibri;">Dockerfile </span><span style="font-family:'宋体';">放到 </span><span style="font-family:Calibri;">Node.js </span><span style="font-family:'宋体';">项目的根目录</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">构建好镜像后</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">就可以直接拿来启动容器运行。但是如果我们还有第二个 </span><span style="font-family:Calibri;">Node.js </span><span style="font-family:'宋体';">项目也差不多呢</span><span style="font-family:Calibri;">?</span><span style="font-family:'宋体';">好吧</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">那就再把这个 </span><span style="font-family:Calibri;">Dockerfile </span><span style="font-family:'宋体';">复制到第二个项目里。那如果有第三个项目呢</span><span style="font-family:Calibri;">?</span><span style="font-family:'宋体';">再复制么</span><span style="font-family:Calibri;">?</span><span style="font-family:'宋体';">文件的副本越多</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">版本控制就越困难</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">让我们继续看这样的场景维护的问题。</span></p> <p>如果第一个 <span style="font-family:Calibri;">Node.js </span><span style="font-family:'宋体';">项目在开发过程中</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">发现这个 </span><span style="font-family:Calibri;">Dockerfile </span><span style="font-family:'宋体';">里存在问题</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">比如敲错字了、或者需要安装额外的包</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">然后开发人员修复了这个 </span><span style="font-family:Calibri;">Dockerfile,</span><span style="font-family:'宋体';">再次构建</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">问题解决。第一个项目没问题了</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">但是第二个项目呢</span><span style="font-family:Calibri;">?</span><span style="font-family:'宋体';">虽然最初 </span><span style="font-family:Calibri;">Dockerfile </span><span style="font-family:'宋体';">是复制、粘贴自第一个项目的</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">但是并不会因为第一个项目修复了他们的 </span><span style="font-family:Calibri;">Dockerfile,</span><span style="font-family:'宋体';">而第二个项目的 </span><span style="font-family:Calibri;">Dockerfile </span><span style="font-family:'宋体';">就会被自动修复。</span></p> <p>那么我们可不可以做一个基础镜像<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">然后各个项目使用这个基础镜像呢</span><span style="font-family:Calibri;">?</span><span style="font-family:'宋体';">这样基础镜像更新</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">各个项目不用同步 </span><span style="font-family:Calibri;">Dockerfile </span><span style="font-family:'宋体';">的变化</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">重新构建后就继承了基础镜像的更新</span><span style="font-family:Calibri;">?</span><span style="font-family:'宋体';">好吧</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">可以</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">让我们看看这样的结果。那么上面的这个 </span><span style="font-family:Calibri;">Dockerfile </span><span style="font-family:'宋体';">就会变为</span><span style="font-family:Calibri;">:</span></p> <p>FROM node:slim</p> <p>RUN mkdir /app</p> <p>WORKDIR /app</p> <p>CMD [ "npm", "start" ]</p> <p>这里我们把项目相关的构建指令拿出来<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">放到子项目里去。假设这个基础镜像的名字为 </span><span style="font-family:Calibri;">my-node </span><span style="font-family:'宋体';">的话</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">各个项目内的自己的 </span><span style="font-family:Calibri;">Dockerfile </span><span style="font-family:'宋体';">就变为</span><span style="font-family:Calibri;">:</span></p> <p>FROM my-node</p> <p>COPY ./package.json /app</p> <p>RUN [ "npm", "install" ]</p> <p>COPY . /app/</p> <p>基础镜像变化后<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">各个项目都用这个 </span><span style="font-family:Calibri;">Dockerfile </span><span style="font-family:'宋体';">重新构建镜像</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">会继承基础镜像的更新。</span></p> <p>那么<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">问题解决了么</span><span style="font-family:Calibri;">?</span><span style="font-family:'宋体';">没有。准确说</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">只解决了一半。如果这个 </span><span style="font-family:Calibri;">Dockerfile </span><span style="font-family:'宋体';">里面有些东西需要调整呢</span><span style="font-family:Calibri;">?</span><span style="font-family:'宋体';">比如 </span><span style="font-family:Calibri;">npm install </span><span style="font-family:'宋体';">都需要加一些参数</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">那怎么办</span><span style="font-family:Calibri;">?</span><span style="font-family:'宋体';">这一行 </span><span style="font-family:Calibri;">RUN </span><span style="font-family:'宋体';">是不可能放入基础镜像的</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">因为涉及到了当前项目的 </span><span style="font-family:Calibri;">./package.json,</span><span style="font-family:'宋体';">难道又要一个个修改么</span><span style="font-family:Calibri;">?</span><span style="font-family:'宋体';">所以说</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">这样制作基础镜像</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">只解决了原来的 </span><span style="font-family:Calibri;">Dockerfile </span><span style="font-family:'宋体';">的前</span><span style="font-family:Calibri;">4</span><span style="font-family:'宋体';">条指令的变化问题</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">而后面三条指令的变化则完全没办法处理。</span></p> <p>ONBUILD <span style="font-family:'宋体';">可以解决这个问题。让我们用 </span><span style="font-family:Calibri;">ONBUILD </span><span style="font-family:'宋体';">重新写一下基础镜像的 </span><span style="font-family:Calibri;">Dockerfile:</span></p> <p>FROM node:slim</p> <p>RUN mkdir /app</p> <p>WORKDIR /app</p> <p>ONBUILD COPY ./package.json /app</p> <p>ONBUILD RUN [ "npm", "install" ]</p> <p>ONBUILD COPY . /app/</p> <p>CMD [ "npm", "start" ]</p> <p>这次我们回到原始的 <span style="font-family:Calibri;">Dockerfile,</span><span style="font-family:'宋体';">但是这次将项目相关的指令加上 </span><span style="font-family:Calibri;">ONBUILD,</span><span style="font-family:'宋体';">这样在构建基础镜像的时候</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">这三行并不会被执行。然后各个项目的 </span><span style="font-family:Calibri;">Dockerfile </span><span style="font-family:'宋体';">就变成了简单地</span><span style="font-family:Calibri;">:</span></p> <p>FROM my-node</p> <p>是的<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">只有这么一行。当在各个项目目录中</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">用这个只有一行的 </span><span style="font-family:Calibri;">Dockerfile </span><span style="font-family:'宋体';">构建镜像时</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">之前基础镜像的那三行 </span><span style="font-family:Calibri;">ONBUILD </span><span style="font-family:'宋体';">就会开始执行</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">成功的将当前项目的代码复制进镜像、并且针对本项目执行 </span><span style="font-family:Calibri;">npm install,</span><span style="font-family:'宋体';">生成应用镜像。</span></p> <h1>5、Docker容器命令</h1> <p>当利用<span style="font-family:Calibri;">docker run</span><span style="font-family:'宋体';">来创建容器时</span><span style="font-family:Calibri;">,Docker </span><span style="font-family:'宋体';">在后台运行的标准操作包括</span><span style="font-family:Calibri;">:</span></p> <p>l 检查本地是否存在指定的镜像<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">不存在就从公有仓库下载。</span></p> <p>l 利用镜像创建并启动一个容器。</p> <p>l 分配一个文件系统<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">并在只读的镜像层外面挂载一层可读写层。</span></p> <p>l 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去。</p> <p>l 从地址池配置一个 <span style="font-family:Calibri;">ip </span><span style="font-family:'宋体';">地址给容器。</span></p> <p>l 执行用户指定的应用程序。</p> <p>l 执行完毕后容器被终止。</p> <p>1、<strong>docker run</strong><br>语法:</p> <ul> <li>docker run [options] IMAGE [command] [args]</li> </ul> <p>OPTIONS说明:</p> <ul> <li>-a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;</li> <li>-d: 后台运行容器,并返回容器ID;</li> <li>-i: 以交互模式运行容器,通常与 -t 同时使用;</li> <li>-t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;</li> <li>--name="nginx-lb": 为容器指定一个名称;</li> <li>--dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;</li> <li>--dns-search example.com: 指定容器DNS搜索域名,默认和宿主一致;</li> <li>-h "mars": 指定容器的hostname;</li> <li>-e username="ritchie": 设置环境变量;</li> <li>--env-file=[]: 从指定文件读入环境变量;</li> <li>--cpuset="0-2" or --cpuset="0,1,2": 绑定容器到指定CPU运行;</li> <li>-m :设置容器使用内存最大值;</li> <li>--net="bridge": 指定容器的网络连接类型,支持 bridge(在容器内部、主机上创建一对网络设备,在容器内部为eth0,而外部则是veth*网络设备,这个设备加在了主机上的Docker0网桥之中,从而实现容器与外部的通信)、host(容器和主机共用一个Network Namespace)、none(拥有自己的Network Namespace,但不为容器进行任何网络配置,需要用户自行添加)、container(容器不与主机共享Network Namespace地址空间,而是与一个指定的容器共享): 四种类型。 相关文章:<strong>四种网络模式</strong> https://blog.csdn.net/noob_f/article/details/52875664</li> <li>--link=[]: 添加链接到另一个容器;</li> <li>--expose=[]: 开放一个端口或一组端口; </li> <li>-p,--publish=[]:容器内的端口服务在主机OS上是无法访问的,这就需要提前对外发布端口,我们也可以认为是端口映射(ip:hostport:containerport)</li> <li>--rm:在容器运行完毕后自动删除容器(这个选项不能与-d同时使用)</li> <li>-v,--volume=[]:容器中的数据会随着容器生命周期的结束而消失,我们可以通过该选项将外部存储映射到容器内,将外部数据给容器访问,或者将容器的数据保存到外部(/host:/container)</li> <li>--volumes-from=[]:从另外一个容器中mount卷</li> <li>-w,--workdir=" ":设置容器中的工作文件夹</li> <li>--name=" ":分配一个容器名字,如果不指定,则会自动生成</li> <li>-u,--user=" ":指定容器运行后的uid或用户名</li> <li>-c,--cpu-shares=0:cpu-shares是一个权重值,当多个容器运行在相同的CPU资源上时,会依据此权重值进行资源分配</li> <li>--restart:设定容器重起策略。 <ul> <li>no<span style="font-family:'宋体';">,默认策略,在容器退出时不重启容器。</span></li> <li>on-failure<span style="font-family:'宋体';">,在容器非正常退出时(退出状态非</span><span style="font-family:Calibri;">0</span><span style="font-family:'宋体';">),才会重启容器。</span></li> <li>on-failure:3<span style="font-family:'宋体';">,在容器非正常退出时重启容器,最多重启</span><span style="font-family:Calibri;">3</span><span style="font-family:'宋体';">次。</span></li> <li>always<span style="font-family:'宋体';">,在容器退出时总是重启容器。</span></li> <li>unless-stopped<span style="font-family:'宋体';">,在容器退出时总是重启容器,但是不考虑在</span><span style="font-family:Calibri;">Docker</span><span style="font-family:'宋体';">守护进程启动时就已经停止了的容器。</span></li> </ul></li> </ul> <p> </p> <h3><strong>-P<span style="font-family:'宋体';">参数 外部访问容器</span></strong></h3> <p>容器中可以运行一些网络应用<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">要让外部也可以访问这些应用</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">可以通过</span><span style="font-family:Calibri;">-P</span><span style="font-family:'宋体';">或</span><span style="font-family:Calibri;">-p</span><span style="font-family:'宋体';">参数来指定端口映射。</span></p> <p>当使用<span style="font-family:Calibri;">-P</span><span style="font-family:'宋体';">标记时</span><span style="font-family:Calibri;">,Docker</span><span style="font-family:'宋体';">会随机映射一个</span><span style="font-family:Calibri;">49000~49900</span><span style="font-family:'宋体';">的端口到内部容器开放的网络端口。</span></p> <p>使用<span style="font-family:Calibri;">docker ps -a</span><span style="font-family:'宋体';">可以看到</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">本地主机的</span><span style="font-family:Calibri;">49155</span><span style="font-family:'宋体';">被映射到了容器的</span><span style="font-family:Calibri;">5000</span><span style="font-family:'宋体';">端口。此时访问本机的</span><span style="font-family:Calibri;">49155</span><span style="font-family:'宋体';">端口即可访问容器内</span><span style="font-family:Calibri;">web</span><span style="font-family:'宋体';">应用提供的界面。</span></p> <h3><strong>-p<span style="font-family:'宋体';">参数 外部访问容器</span></strong></h3> <p>-p<span style="font-family:'宋体';">则可以指定要映射的端口</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">并且</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">在一个指定端口上只可以绑定一个容器。支持的格式有</span><span style="font-family:Calibri;">ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort</span><span style="font-family:'宋体';">。</span></p> <p> </p> <p>使用<span style="font-family:Calibri;">hostPort:containerPort</span><span style="font-family:'宋体';">格式,本地的</span><span style="font-family:Calibri;">5000</span><span style="font-family:'宋体';">端口映射到容器的</span><span style="font-family:Calibri;">5000</span><span style="font-family:'宋体';">端口</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">可以执行:</span></p> <p>$ docker run -d -p 5000:5000 training/webapp python app.py</p> <p>此时默认会绑定本地所有接口上的所有地址。</p> <p> </p> <p>可以使用<span style="font-family:Calibri;">ip:hostPort:containerPort</span><span style="font-family:'宋体';">格式,指定映射使用一个特定地址</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">比如 </span><span style="font-family:Calibri;">localhost </span><span style="font-family:'宋体';">地址</span><span style="font-family:Calibri;">127.0.0.1,</span><span style="font-family:'宋体';">可以执行</span><span style="font-family:Calibri;">:</span></p> <p>$ docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py</p> <p> </p> <p>使用<span style="font-family:Calibri;">ip::containerPort</span><span style="font-family:'宋体';">格式,绑定</span><span style="font-family:Calibri;">localhost</span><span style="font-family:'宋体';">的任意端口到容器的</span><span style="font-family:Calibri;">5000</span><span style="font-family:'宋体';">端口</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">本地主机会自动分配一个端口。</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">可以执行</span><span style="font-family:Calibri;">:</span></p> <p>$ docker run -d -p 127.0.0.1::5000 training/webapp python app.py</p> <p> </p> <p>还可以使用<span style="font-family:Calibri;">udp</span><span style="font-family:'宋体';">标记来指定</span><span style="font-family:Calibri;">udp</span><span style="font-family:'宋体';">端口</span></p> <p>$ docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py</p> <p> </p> <p>-p<span style="font-family:'宋体';">标记可以多次使用来绑定多个端口</span></p> <p> </p> <p><strong>2、<strong>docker </strong>start</strong><br>语法:</p> <ul> <li>docker start [-i] [-a] <container(s)></li> </ul> <p>选项基本与run一样。</p> <p>3、<strong>docker </strong><strong>stop</strong></p> <p>4、<strong>docker </strong><strong>restart</strong><br>选项基本与run一样。</p> <p>5、<strong>docker </strong><strong>attach </strong>: 连接到正在运行中的容器。<br>选项:</p> <ul> <li>--sig-proxy=false,确保CTRL-D或CTRL-C不会关闭容器。</li> </ul> <p> </p> <p>6、<strong>docker </strong><strong>ps</strong> : 列出容器<br>语法:</p> <ul> <li>docker ps [OPTIONS]</li> </ul> <p>OPTIONS说明:</p> <ul> <li>-a,--all :显示所有的容器,包括未运行的。</li> <li>-f :根据条件过滤显示的内容。</li> <li>--format :指定返回值的模板文件。</li> <li>-l,--latest :显示最近创建的容器。</li> <li>-n :列出最近创建的n个容器。</li> <li>--no-trunc :不截断输出。</li> <li>-q,--quit :静默模式,只显示容器编号。</li> <li>-s,--size :显示总的文件大小。</li> <li>--before=" " :显示在某个容器ID之前启动的所有容器,包括停止的容器</li> <li>--after=" " :显示在某个容器ID之后启动的所有容器,包括停止的容器</li> </ul> <p> </p> <p>7、<strong>docker </strong><strong>inspect</strong> : 获取容器/镜像的元数据。<br>语法:</p> <ul> <li>docker inspect [OPTIONS] NAME|ID [NAME|ID...]</li> </ul> <p>OPTIONS说明:</p> <ul> <li>-f :指定返回值的模板文件。</li> <li>-s :显示总的文件大小。</li> <li>--type :为指定类型返回JSON。</li> </ul> <p> 实例,获取镜像mysql:5.6的元信息:<br>$ docker inspect mysql:5.6<br>实例,获取正在运行的容器mymysql的 IP:<br>$ docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mymysql</p> <h2><strong>7、docker rm <span style="font-family:'方正黑体_GBK';">删除容器</span></strong></h2> <p>$ docker rm trusting_newton</p> <p>trusting_newton</p> <p>如果要删除一个运行中的容器<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">可以添加 </span><span style="font-family:Calibri;">-f </span><span style="font-family:'宋体';">参数。</span><span style="font-family:Calibri;">Docker </span><span style="font-family:'宋体';">会发送 </span><span style="font-family:Calibri;">SIGKILL </span><span style="font-family:'宋体';">信号给容器。</span></p> <h2><strong>8、docker exec <span style="font-family:'方正黑体_GBK';">进入容器</span></strong></h2> <p>在使用 <span style="font-family:Calibri;">-d </span><span style="font-family:'宋体';">参数时</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">容器启动后会进入后台。某些时候需要进入容器进行操作</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">此时需要使用</span><span style="font-family:Calibri;">docker exec </span><span style="font-family:'宋体';">命令。</span></p> <p>docker exec<span style="font-family:'宋体';">命令只用</span><span style="font-family:Calibri;">-i</span><span style="font-family:'宋体';">交互式操作参数时</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">由于没有分配伪终端</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">界面没有我们熟悉的</span><span style="font-family:Calibri;">Linux</span><span style="font-family:'宋体';">命令提示符</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">但命令执行结果仍然可以返回。当</span><span style="font-family:Calibri;">-i</span><span style="font-family:'宋体';">交互式操作、</span><span style="font-family:Calibri;">-t</span><span style="font-family:'宋体';">终端参数一起使用时</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">则可以看到我们熟悉的 </span><span style="font-family:Calibri;">Linux </span><span style="font-family:'宋体';">命令提示符。</span></p> <p>$ docker run -dit ubuntu</p> <p>69d137adef7a8a689cbcb059e94da5489d3cddd240ff675c640c8d96e84fe1f6</p> <p>$ docker ps</p> <p>CONTAINER IDIMAGE COMMAND CREATED STATUS</p> <p>PORTS NAMES</p> <p>69d137adef7aubuntu:latest "/bin/bash" 18 seconds agoUp 17 </p> <p>seconds zealous_swirles</p> <p>$ <strong>docker exec -i 69d1 bash</strong></p> <p>ls</p> <p>bin</p> <p>boot</p> <p>dev</p> <p>...</p> <p>$ <strong>docker exec -it 69d1 bash</strong></p> <p>root@69d137adef7a:/#</p> <h2><strong>9、docker diff <span style="font-family:'方正黑体_GBK';">查看容器中具体的改动</span></strong></h2> <p>我们修改了容器的文件<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">也就是改动了容器的存储层。我们可以通过</span><span style="font-family:Calibri;">docker diff</span><span style="font-family:'宋体';">命令看到具体的改动。</span></p> <p>$ docker diff webserver</p> <p> </p> <h2><strong>10、docker port <span style="font-family:'方正黑体_GBK';">查看映射地址</span><span style="font-family:'DejaVu Sans';">:</span><span style="font-family:'方正黑体_GBK';">端口配置</span></strong></h2> <p>$ docker port nostalgic_morse 5000</p> <p>127.0.0.1:49155.</p> <h2><strong>11、docker logs <span style="font-family:'方正黑体_GBK';">获取容器的输出信息</span></strong></h2> <p> </p> <h2><strong>12、docker export <span style="font-family:'方正黑体_GBK';">导出本地某个容器</span></strong></h2> <p>$ docker export 7691a814370e > ubuntu.tar</p> <p>这样将导出容器快照到本地文件。</p> <h2><strong>13、docker commit <span style="font-family:'方正黑体_GBK';">将容器保存为镜像</span></strong></h2> <p>语法格式为<span style="font-family:Calibri;">:</span></p> <p>docker commit [<span style="font-family:'宋体';">选项</span><span style="font-family:Calibri;">] <</span><span style="font-family:'宋体';">容器</span><span style="font-family:Calibri;">ID</span><span style="font-family:'宋体';">或容器名</span><span style="font-family:Calibri;">> [<</span><span style="font-family:'宋体';">仓库名</span><span style="font-family:Calibri;">>[:<</span><span style="font-family:'宋体';">标签</span><span style="font-family:Calibri;">>]]</span></p> <p>我们可以用下面的命令将容器保存为镜像<span style="font-family:Calibri;">:</span></p> <p>$ docker commit --author "Tao Wang <twang2218@gmail.com>" --message "<span style="font-family:'宋体';">修改了默认网页</span><span style="font-family:Calibri;">" webserver nginx:v2</span></p> <p>sha256:07e33465974800ce65751acc279adc6ed2dc5ed4e0838f8b86f0c87aa1795214</p> <p>其中<span style="font-family:Calibri;">--author</span><span style="font-family:'宋体';">是指定修改的作者</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">而</span><span style="font-family:Calibri;">--message</span><span style="font-family:'宋体';">则是记录本次修改的内容。这点和</span><span style="font-family:Calibri;">git</span><span style="font-family:'宋体';">版本控制相似</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">不过这里这些信息可以省略留空。</span></p> <h2><strong>14、docker import <span style="font-family:'方正黑体_GBK';">从容器快照文件中再导入为镜像</span></strong></h2> <p>$ cat ubuntu.tar | docker import - test/ubuntu:v1.0</p> <p>此外<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">也可以通过指定 </span><span style="font-family:Calibri;">URL </span><span style="font-family:'宋体';">或者某个目录来导入</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">例如</span></p> <p>$ docker import http://example.com/exampleimage.tgz example/imagerepo</p> <p>注<span style="font-family:Calibri;">:</span><span style="font-family:'宋体';">用户既可以使用 </span><span style="font-family:Calibri;">docker load </span><span style="font-family:'宋体';">来导入镜像存储文件到本地镜像库</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">也可以使用 </span><span style="font-family:Calibri;">docker import </span><span style="font-family:'宋体';">来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息</span><span style="font-family:Calibri;">(</span><span style="font-family:'宋体';">即仅保存容器当时的快照状态</span><span style="font-family:Calibri;">),</span><span style="font-family:'宋体';">而镜像存储文件将保存完整记录</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">体积也要大。此外</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">从容器快照文件导入时可以重新指定标签等元数据信息。</span></p> <p> </p> <h1><strong>6、仓库 <span style="font-family:Calibri;">r</span></strong><strong>egistry</strong></h1> <p>镜像构建完成后<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">可以很容易的在当前宿主机上运行</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">但是</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">如果需要在其它服务器上使用这个镜像</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">我们就需要一个集中的存储、分发镜像的服务</span><span style="font-family:Calibri;">,Docker Registry </span><span style="font-family:'宋体';">就是这样的服务。</span></p> <p>一个 <span style="font-family:Calibri;">Docker Registry </span><span style="font-family:'宋体';">中可以包含多个仓库</span><span style="font-family:Calibri;">(Repository);</span><span style="font-family:'宋体';">每个仓库可以包含多个标签</span><span style="font-family:Calibri;">(Tag);</span><span style="font-family:'宋体';">每个标签对应一个镜像。</span></p> <p>通常<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">一个仓库会包含同一个软件不同版本的镜像</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">而标签就常用于对应该软件的各个版本。我们可以通过</span><span style="font-family:Calibri;"><</span><span style="font-family:'宋体';">仓库名</span><span style="font-family:Calibri;">>:<</span><span style="font-family:'宋体';">标签</span><span style="font-family:Calibri;">></span><span style="font-family:'宋体';">的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">将以</span><span style="font-family:Calibri;">latest</span><span style="font-family:'宋体';">作为默认标签。</span></p> <p>以 <span style="font-family:Calibri;">Ubuntu </span><span style="font-family:'宋体';">镜像 为例</span><span style="font-family:Calibri;">,ubuntu</span><span style="font-family:'宋体';">是仓库的名字</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">其内包含有不同的版本标签</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">如</span><span style="font-family:Calibri;">,14.04,16.04</span><span style="font-family:'宋体';">。我们可以通过</span><span style="font-family:Calibri;">ubuntu:14.04,</span><span style="font-family:'宋体';">或者</span><span style="font-family:Calibri;">ubuntu:16.04</span><span style="font-family:'宋体';">来具体指定所需哪个版本的镜像。如果忽略了标签</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">比如</span><span style="font-family:Calibri;">ubuntu,</span><span style="font-family:'宋体';">那将视为</span><span style="font-family:Calibri;">ubuntu:latest</span><span style="font-family:'宋体';">。</span></p> <p>仓库名经常以 两段式路径 形式出现<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">比如</span><span style="font-family:Calibri;">jwilder/nginx-proxy,</span><span style="font-family:'宋体';">前者往往意味着 </span><span style="font-family:Calibri;">Docker</span> Registry <span style="font-family:'宋体';">多用户环境下的用户名</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">后者则往往是对应的软件名。但这并非绝对</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">取决于所使用的具体 </span><span style="font-family:Calibri;">Docker Registry </span><span style="font-family:'宋体';">的软件或服务。</span></p> <h2><strong>公共仓库</strong><strong> </strong><strong>Docker Hub</strong></h2> <p>Docker Registry<span style="font-family:'宋体';">公开服务是开放给用户使用、允许用户管理镜像的 </span><span style="font-family:Calibri;">Registry </span><span style="font-family:'宋体';">服务。一般这类公开服务允许用户免费上传、下载公开的镜像</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">并可能提供收费服务供用户管理私有镜像。</span></p> <p>最常使用的 <span style="font-family:Calibri;">Registry </span><span style="font-family:'宋体';">公开服务是官方的 </span><span style="font-family:Calibri;">Docker Hub,</span><span style="font-family:'宋体';">这也是默认的 </span><span style="font-family:Calibri;">Registry,</span><span style="font-family:'宋体';">并拥有大量的高质量的官方镜像。除此以外</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">还有 </span><span style="font-family:Calibri;">CoreOS </span><span style="font-family:'宋体';">的 </span><span style="font-family:Calibri;">Quay.io,CoreOS </span><span style="font-family:'宋体';">相关的镜像存储在这里</span>。Google <span style="font-family:'宋体';">的 </span><span style="font-family:Calibri;">Google Container Registry,Kubernetes </span><span style="font-family:'宋体';">的镜像使用的就是这个服务。</span></p> <p>由于某些原因<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">在国内访问这些服务可能会比较慢。国内的一些云服务商提供了针对</span>Docker Hub的镜像服务<span style="font-family:Calibri;">(Registry Mirror),</span><span style="font-family:'宋体';">这些镜像服务被称为加速器。常见的有 阿里云加速器、</span><span style="font-family:Calibri;">DaoCloud </span><span style="font-family:'宋体';">加速器 等。使用加速器会直接从国内的地址下载</span>Docker Hub的镜像<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">比直接从</span>Docker Hub下载速度会提高很多。在 安装 <span style="font-family:Calibri;">Docker </span><span style="font-family:'宋体';">一节中有详细的配置方法。</span></p> <p>国内也有一些云服务商提供类似于Docker Hub的公开服务。比如 时速云镜像仓库、网易云镜像服务、<span style="font-family:Calibri;">DaoCloud </span><span style="font-family:'宋体';">镜像市场、阿里云镜像库 等。</span></p> <p>目前 <span style="font-family:Calibri;">Docker </span><span style="font-family:'宋体';">官方维护了一个公共仓库 </span><span style="font-family:Calibri;">Docker Hub,</span><span style="font-family:'宋体';">其中已经包括了数量超过 </span><span style="font-family:Calibri;">15,000 </span><span style="font-family:'宋体';">的镜像。大部分需求都可以通过在</span>Docker Hub中直接下载镜像来实现。</p> <h3><strong>注册</strong></h3> <p>可以在 <span style="font-family:Calibri;">https://cloud.docker.com </span><span style="font-family:'宋体';">免费注册一个 </span><span style="font-family:Calibri;">Docker </span><span style="font-family:'宋体';">账号。</span></p> <h3><strong>1、docker login</strong><strong> </strong><strong>登录</strong></h3> <p>可以通过执行<span style="font-family:Calibri;">docker login</span><span style="font-family:'宋体';">命令交互式的输入用户名及密码来完成在命令行界面登录</span><span style="font-family:Calibri;">Docker Hub</span><span style="font-family:'宋体';">。</span></p> <h3><strong>2、docker logout</strong><strong> </strong><strong>退出登录</strong></h3> <p>可以通过<span style="font-family:Calibri;">docker logout</span><span style="font-family:'宋体';">退出登录。</span></p> <h3><strong>3、docker search</strong><strong> </strong><strong>查找官方仓库中的镜像</strong></h3> <p>可以通过<span style="font-family:Calibri;">docker search</span><span style="font-family:'宋体';">命令来查找官方仓库中的镜像</span>。例如以<span style="font-family:Calibri;">centos</span><span style="font-family:'宋体';">为关键词进行搜索</span><span style="font-family:Calibri;">:</span></p> <p>$ docker search centos</p> <p>可以看到返回了很多包含关键字的镜像<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">其中包括镜像名字、描述、收藏数</span><span style="font-family:Calibri;">(</span><span style="font-family:'宋体';">表示该镜像的受关注程度</span><span style="font-family:Calibri;">)</span><span style="font-family:'宋体';">、是否官方创建、是否自动创建。</span></p> <p>官方的镜像说明是官方项目组创建和维护的<span style="font-family:Calibri;">,automated </span><span style="font-family:'宋体';">资源允许用户验证镜像的来源和内容。</span></p> <p>根据是否是官方提供<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">可将镜像资源分为两类。</span></p> <p>一种是类似<span style="font-family:Calibri;">centos</span><span style="font-family:'宋体';">这样的镜像</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">被称为基础镜像或根镜像。这些基础镜像由 </span><span style="font-family:Calibri;">Docker </span><span style="font-family:'宋体';">公司创建、验证、支持、提供。这样的镜像往往使用单个单词作为名字。</span></p> <p>还有一种类型<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">比如</span><span style="font-family:Calibri;">tianon/centos</span><span style="font-family:'宋体';">镜像</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">它是由 </span><span style="font-family:Calibri;">Docker </span><span style="font-family:'宋体';">的用户创建并维护的</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">往往带有用户名称前缀。可以通过前缀</span><span style="font-family:Calibri;">username/</span><span style="font-family:'宋体';">来指定使用某个用户提供的镜像</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">比如 </span><span style="font-family:Calibri;">tianon </span><span style="font-family:'宋体';">用户。</span></p> <p>另外<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">在查找的时候通过</span><span style="font-family:Calibri;">--filter=stars=N</span><span style="font-family:'宋体';">参数可以指定仅显示收藏数量为</span><span style="font-family:Calibri;">N</span><span style="font-family:'宋体';">以上的镜像。</span></p> <h3><strong>4、docker pul</strong><strong>l </strong><strong>拉取镜像</strong></h3> <p>利用<span style="font-family:Calibri;">docker pull</span><span style="font-family:'宋体';">命令来将它下载到本地。</span>例如下载官方<span style="font-family:Calibri;">centos</span><span style="font-family:'宋体';">镜像到本地</span>:</p> <p>$ docker pull centos</p> <h3><strong>5、docker push</strong><strong> </strong><strong>推送镜像</strong></h3> <p>用户也可以在登录后通过<span style="font-family:Calibri;">docker push</span><span style="font-family:'宋体';">命令来将自己的镜像推送到 </span><span style="font-family:Calibri;">Docker Hub</span><span style="font-family:'宋体';">。以下命令中的</span><span style="font-family:Calibri;">username</span><span style="font-family:'宋体';">请替换为你的 </span><span style="font-family:Calibri;">Docker </span><span style="font-family:'宋体';">账号用户名。</span></p> <p>$ docker tag ubuntu:17.10 username/ubuntu:17.10</p> <p>$ docker images</p> <p>$ docker push username/ubuntu:17.10</p> <p>$ docker search username</p> <h3><strong>6、自动创建</strong></h3> <p>自动创建<span style="font-family:Calibri;">(Automated Builds)</span><span style="font-family:'宋体';">功能对于需要经常升级镜像内程序来说</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">十分方便。</span></p> <p>有时候<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">用户创建了镜像</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">安装了某个软件</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">如果软件发布新版本则需要手动更新镜像。</span></p> <p>而自动创建允许用户通过Docker Hub指定跟踪一个目标网站<span style="font-family:Calibri;">(</span><span style="font-family:'宋体';">目前支持 </span><span style="font-family:Calibri;">GitHub </span><span style="font-family:'宋体';">或</span><span style="font-family:Calibri;">BitBucket)</span><span style="font-family:'宋体';">上的项目</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">一旦项目发生新的提交或者创建新的标签</span><span style="font-family:Calibri;">(tag),Docker Hub </span><span style="font-family:'宋体';">会自动构建镜像并推送到</span>Docker Hub中。</p> <p>要配置自动创建<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">包括如下的步骤</span><span style="font-family:Calibri;">:</span></p> <p>l 创建并登录 <span style="font-family:Calibri;">Docker Hub,</span><span style="font-family:'宋体';">以及目标网站</span><span style="font-family:Calibri;">;</span></p> <p>l 在目标网站中连接帐户到 <span style="font-family:Calibri;">Docker Hub;</span></p> <p>l 在Docker Hub中 配置一个自动创建<span style="font-family:Calibri;">;</span></p> <p>l 选取一个目标网站中的项目<span style="font-family:Calibri;">(</span><span style="font-family:'宋体';">需要含</span><span style="font-family:Calibri;">Dockerfile)</span><span style="font-family:'宋体';">和分支</span><span style="font-family:Calibri;">;</span></p> <p>l 指定<span style="font-family:Calibri;">Dockerfile</span><span style="font-family:'宋体';">的位置</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">并提交创建。</span></p> <p>之后<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">可以在</span>Docker Hub的 自动创建页面 中跟踪每次创建的状态。</p> <h2><strong>私有仓库</strong></h2> <p>除了使用公开服务外<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">用户还可以在本地搭建私有 </span><span style="font-family:Calibri;">Docker Registry</span><span style="font-family:'宋体';">。</span><span style="font-family:Calibri;">Docker </span><span style="font-family:'宋体';">官方提供了</span><span style="font-family:Calibri;">Docker Registry </span><span style="font-family:'宋体';">镜像</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">可以直接使用做为私有 </span><span style="font-family:Calibri;">Registry </span><span style="font-family:'宋体';">服务。</span></p> <p>开源的 <span style="font-family:Calibri;">Docker Registry </span><span style="font-family:'宋体';">镜像只提供了 </span><span style="font-family:Calibri;">Docker Registry API </span><span style="font-family:'宋体';">的服务端实现</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">足以支持</span><span style="font-family:Calibri;">docker</span><span style="font-family:'宋体';">命令</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">不影响使用。但不包含图形界面</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">以及镜像维护、用户管理、访问控制等高级功能。在官方的商业化版本 </span><span style="font-family:Calibri;">Docker Trusted Registry </span><span style="font-family:'宋体';">中</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">提供了这些高级功能。</span></p> <p>除了官方的 <span style="font-family:Calibri;">Docker Registry </span><span style="font-family:'宋体';">外</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">还有第三方软件实现了 </span><span style="font-family:Calibri;">Docker Registry API,</span><span style="font-family:'宋体';">甚至提供了用户界面以及一些高级功能。比如</span><span style="font-family:Calibri;">,VMWare Harbor </span><span style="font-family:'宋体';">和 </span><span style="font-family:Calibri;">Sonatype Nexus</span><span style="font-family:'宋体';">。</span></p> <p>本文内容基于<span style="font-family:Calibri;">docker-registryv2.x </span><span style="font-family:'宋体';">版本。</span></p> <h3><strong>1、运行<span style="font-family:Calibri;">docker-registry</span></strong></h3> <p>通过获取官方<span style="font-family:Calibri;">registry</span><span style="font-family:'宋体';">镜像来运行。</span></p> <p>$ docker run -d -p 5000:5000 --restart=always -v /opt/data/registry:/var/lib/registry --name registry registry</p> <p>这将使用官方的<span style="font-family:Calibri;">registry</span><span style="font-family:'宋体';">镜像来启动私有仓库。</span>-v<span style="font-family:'宋体';">参数,</span>将上传的镜像文件放到指定的本地<span style="font-family:Calibri;">/opt/data/registry</span><span style="font-family:'宋体';">目录</span>,默认情况下<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">仓库会被创建在容器的</span><span style="font-family:Calibri;">/var/lib/registry</span><span style="font-family:'宋体';">目录下</span>。</p> <h3><strong>2、docker </strong><strong>push</strong><strong> </strong><strong>上传镜像</strong></h3> <p>创建好私有仓库之后<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">就可以使用</span><span style="font-family:Calibri;">docker tag</span><span style="font-family:'宋体';">来标记一个镜像</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">然后推送它到仓库。例如私有仓库地址为</span><span style="font-family:Calibri;">127.0.0.1:5000</span><span style="font-family:'宋体';">。</span></p> <p>先在本机查看已有的镜像。</p> <p>$<strong> docker </strong><strong>images</strong></p> <p>REPOSITORY    TAG    IMAGE    IDCREATED    VIRTUAL    SIZE</p> <p>ubuntu    latest   ba5877dc9bec6    weeks ago    192.7 MB</p> <p> </p> <p>使用<span style="font-family:Calibri;">docker tag</span><span style="font-family:'宋体';">将</span><span style="font-family:Calibri;">ubuntu:latest</span><span style="font-family:'宋体';">这个镜像标记为</span><span style="font-family:Calibri;">127.0.0.1:5000/ubuntu:latest</span><span style="font-family:'宋体';">。</span></p> <p>格式为<span style="font-family:Calibri;">docker tag IMAGE[:TAG] [REGISTRY_HOST[:REGISTRY_PORT]/]REPOSITORY[:TAG]</span><span style="font-family:'宋体';">。</span></p> <p>$ <strong>docker tag ubuntu:latest 127.0.0.1:5000/ubuntu:latest</strong></p> <p>$ <strong>docker </strong><strong>images</strong></p> <p> </p> <p>使用<span style="font-family:Calibri;">docker push</span><span style="font-family:'宋体';">上传标记的镜像。</span></p> <p>$ <strong>docker push 127.0.0.1:5000/ubuntu:latest</strong></p> <p> </p> <h3><strong>3、curl</strong><strong> </strong><strong>搜索镜像</strong></h3> <p>用<span style="font-family:Calibri;">curl</span><span style="font-family:'宋体';">查看仓库中的镜像。可以看到</span><span style="font-family:Calibri;">{"repositories":["ubuntu"]},</span><span style="font-family:'宋体';">表明镜像已经被成功上传了。</span>或者进入私有仓库容器/var/lib/registry<span style="font-family:'宋体';">目录下</span>查看。</p> <p>$ <strong>curl 127.0.0.1:5000/v2/_catalog</strong></p> <p>{"repositories":["ubuntu"]}</p> <h3><strong>4、docker </strong><strong>pull <span style="font-family:'宋体';">下载镜像</span></strong></h3> <p>先删除已有镜像<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">再尝试从私有仓库中下载这个镜像。</span></p> <p>$ docker image rm 127.0.0.1:5000/ubuntu:latest</p> <p> </p> <p>$ <strong>docker pull 127.0.0.1:5000/ubuntu:latest</strong></p> <p> </p> <p>$ docker images</p> <p> </p> <h3><strong>5、向</strong><strong>其他主机</strong><strong>的私有仓库推送</strong></h3> <p>如果你不想使用<span style="font-family:Calibri;">127.0.0.1:5000</span><span style="font-family:'宋体';">作为仓库地址</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">比如想让本网段的其他主机也能把镜像推送到私有仓库。你就得把例如</span><span style="font-family:Calibri;">192.168.199.100:5000</span><span style="font-family:'宋体';">这样的内网地址作为私有仓库地址</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">这时你会发现无法成功推送镜像。</span></p> <p>这是因为 <span style="font-family:Calibri;">Docker </span><span style="font-family:'宋体';">默认不允许非</span><span style="font-family:Calibri;">HTTPS</span><span style="font-family:'宋体';">方式推送镜像。我们可以通过 </span><span style="font-family:Calibri;">Docker </span><span style="font-family:'宋体';">的配置选项来取消这个限制</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">或者查看下一节配置能够通过</span><span style="font-family:Calibri;">HTTPS</span><span style="font-family:'宋体';">访问的私有仓库。</span></p> <p><strong>Ubuntu 14.04, Debian 7 Wheezy</strong></p> <p>对于使用<span style="font-family:Calibri;">upstart</span><span style="font-family:'宋体';">的系统而言</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">编辑</span><span style="font-family:Calibri;">/etc/default/docker</span><span style="font-family:'宋体';">文件</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">在其中的</span><span style="font-family:Calibri;">DOCKER_OPTS </span><span style="font-family:'宋体';">中增加如下内容</span><span style="font-family:Calibri;">:</span></p> <p>DOCKER_OPTS="--registry-mirror=https://registry.docker-cn.com --insecure-registries=192.168.199.100:5000"</p> <p>重新启动服务。</p> <p>$ sudo service docker restart</p> <p><strong>Ubuntu 16.04+, Debian 8+, centos 7</strong></p> <p>对于使用<span style="font-family:Calibri;">systemd</span><span style="font-family:'宋体';">的系统</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">请在</span><span style="font-family:Calibri;">/etc/docker/daemon.json</span><span style="font-family:'宋体';">中写入如下内容</span><span style="font-family:Calibri;">(</span><span style="font-family:'宋体';">如果文件不存在请新建该文件</span><span style="font-family:Calibri;">)</span></p> <p>{</p> <p>"registry-mirror": [</p> <p> "https://registry.docker-cn.com"</p> <p>],</p> <p>"insecure-registries": [</p> <p> "192.168.199.100:5000"</p> <p>]</p> <p>}</p> <p>注意<span style="font-family:Calibri;">:</span><span style="font-family:'宋体';">该文件必须符合</span><span style="font-family:Calibri;">json</span><span style="font-family:'宋体';">规范</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">否则 </span><span style="font-family:Calibri;">Docker </span><span style="font-family:'宋体';">将不能启动。</span></p> <p><strong>其他</strong></p> <p>对于 <span style="font-family:Calibri;">Docker for Windows </span><span style="font-family:'宋体';">、 </span><span style="font-family:Calibri;">Docker for Mac </span><span style="font-family:'宋体';">在设置中编辑</span><span style="font-family:Calibri;">daemon.json</span><span style="font-family:'宋体';">增加和上边一样的字符串即可。</span></p> <h2><strong><span style="text-decoration:line-through;">私有仓库高级配置</span></strong></h2> <p><span style="text-decoration:line-through;">上一节我们搭建了一个具有基础功能的私有仓库<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">本小节我们来使用</span><span style="font-family:Calibri;">Docker Compose</span><span style="font-family:'宋体';">搭建一个拥有权限认证、</span><span style="font-family:Calibri;">TLS </span><span style="font-family:'宋体';">的私有仓库。</span></span></p> <p><span style="text-decoration:line-through;">新建一个文件夹<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">以下步骤均在该文件夹中进行。</span></span></p> <h3><strong><span style="text-decoration:line-through;">准备站点证书</span></strong></h3> <p><span style="text-decoration:line-through;">如果你拥有一个域名<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">国内各大云服务商均提供免费的站点证书。你也可以使用</span><span style="font-family:Calibri;">openssl</span><span style="font-family:'宋体';">自行签发证书。</span></span></p> <p><span style="text-decoration:line-through;">这里假设我们将要搭建的私有仓库地址为<span style="font-family:Calibri;">docker.domain.com,</span><span style="font-family:'宋体';">下面我们介绍使用</span><span style="font-family:Calibri;">openssl</span><span style="font-family:'宋体';">自行签发</span><span style="font-family:Calibri;">docker.domain.com</span><span style="font-family:'宋体';">的站点 </span><span style="font-family:Calibri;">SSL </span><span style="font-family:'宋体';">证书。</span></span></p> <p><span style="text-decoration:line-through;"> </span></p> <p><span style="text-decoration:line-through;">第一步创建<span style="font-family:Calibri;">CA</span><span style="font-family:'宋体';">私钥。</span></span></p> <p><span style="text-decoration:line-through;">$ openssl genrsa -out "root-ca.key" 4096</span></p> <p><span style="text-decoration:line-through;"> </span></p> <p><span style="text-decoration:line-through;">第二步利用私钥创建<span style="font-family:Calibri;">CA</span><span style="font-family:'宋体';">根证书请求文件。</span></span></p> <p><span style="text-decoration:line-through;">$ openssl req \</span></p> <p><span style="text-decoration:line-through;"> -new -key "root-ca.key" \</span></p> <p><span style="text-decoration:line-through;"> -out "root-ca.csr" -sha256 \</span></p> <p><span style="text-decoration:line-through;"> -subj '/C=CN/ST=Shanxi/L=Datong/O=Your Company Name/CN=Your Company Name Doc</span></p> <p><span style="text-decoration:line-through;">ker Registry CA'</span></p> <p><span style="text-decoration:line-through;">以上命令中<span style="font-family:Calibri;">-subj</span><span style="font-family:'宋体';">参数里的</span><span style="font-family:Calibri;">/C</span><span style="font-family:'宋体';">表示国家</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">如</span><span style="font-family:Calibri;">CN;/ST</span><span style="font-family:'宋体';">表示省</span><span style="font-family:Calibri;">;/L</span><span style="font-family:'宋体';">表示城市或者地区</span><span style="font-family:Calibri;">;/O</span><span style="font-family:'宋体';">表示组织名</span><span style="font-family:Calibri;">;/CN</span><span style="font-family:'宋体';">通用名称。</span></span></p> <p><span style="text-decoration:line-through;"> </span></p> <p><span style="text-decoration:line-through;">第三步配置<span style="font-family:Calibri;">CA</span><span style="font-family:'宋体';">根证书</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">新建</span><span style="font-family:Calibri;">root-ca.cnf</span><span style="font-family:'宋体';">。</span></span></p> <p><span style="text-decoration:line-through;">[root_ca]</span></p> <p><span style="text-decoration:line-through;">basicConstraints = critical,CA:TRUE,pathlen:1</span></p> <p><span style="text-decoration:line-through;">keyUsage = critical, nonRepudiation, cRLSign, keyCertSign</span></p> <p><span style="text-decoration:line-through;">subjectKeyIdentifier=hash</span></p> <p><span style="text-decoration:line-through;"> </span></p> <p><span style="text-decoration:line-through;">第四步签发根证书。</span></p> <p><span style="text-decoration:line-through;">$ openssl x509 -req-days 3650-in "root-ca.csr" \</span></p> <p><span style="text-decoration:line-through;">-signkey "root-ca.key" -sha256 -out "root-ca.crt" \</span></p> <p><span style="text-decoration:line-through;">-extfile "root-ca.cnf" -extensions \</span></p> <p><span style="text-decoration:line-through;">root_ca</span></p> <p><span style="text-decoration:line-through;"> </span></p> <p><span style="text-decoration:line-through;">第五步生成站点<span style="font-family:Calibri;">SSL</span><span style="font-family:'宋体';">私钥。</span></span></p> <p><span style="text-decoration:line-through;">$ openssl genrsa -out "docker.domain.com.key" 4096</span></p> <p><span style="text-decoration:line-through;"> </span></p> <p><span style="text-decoration:line-through;">第六步使用私钥生成证书请求文件。</span></p> <p><span style="text-decoration:line-through;">$ openssl req -new -key "docker.domain.com.key" -out "site.csr" -sha256 \</span></p> <p><span style="text-decoration:line-through;"> -subj '/C=CN/ST=Shanxi/L=Datong/O=Your Company Name/CN=docker.domain.com'</span></p> <p><span style="text-decoration:line-through;"> </span></p> <p><span style="text-decoration:line-through;">第七步配置证书<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">新建</span><span style="font-family:Calibri;">site.cnf</span><span style="font-family:'宋体';">文件。</span></span></p> <p><span style="text-decoration:line-through;">[server]</span></p> <p><span style="text-decoration:line-through;">authorityKeyIdentifier=keyid,issuer</span></p> <p><span style="text-decoration:line-through;">basicConstraints = critical,CA:FALSE</span></p> <p><span style="text-decoration:line-through;">extendedKeyUsage=serverAuth</span></p> <p><span style="text-decoration:line-through;">keyUsage = critical, digitalSignature, keyEncipherment</span></p> <p><span style="text-decoration:line-through;">subjectAltName = DNS:docker.domain.com, IP:127.0.0.1</span></p> <p><span style="text-decoration:line-through;">subjectKeyIdentifier=hash</span></p> <p><span style="text-decoration:line-through;"> </span></p> <p><span style="text-decoration:line-through;">第八步签署站点<span style="font-family:Calibri;">SSL</span><span style="font-family:'宋体';">证书。</span></span></p> <p><span style="text-decoration:line-through;">$ openssl x509 -req -days 750 -in "site.csr" -sha256 \</span></p> <p><span style="text-decoration:line-through;"> -CA "root-ca.crt" -CAkey "root-ca.key"-CAcreateserial \</span></p> <p><span style="text-decoration:line-through;"> -out "docker.domain.com.crt" -extfile "site.cnf" -extensions server</span></p> <p><span style="text-decoration:line-through;"> </span></p> <p><span style="text-decoration:line-through;">这样已经拥有了<span style="font-family:Calibri;">docker.domain.com</span><span style="font-family:'宋体';">的网站 </span><span style="font-family:Calibri;">SSL </span><span style="font-family:'宋体';">私钥</span><span style="font-family:Calibri;">docker.domain.com.key</span><span style="font-family:'宋体';">和 </span><span style="font-family:Calibri;">SSL </span><span style="font-family:'宋体';">证书 </span><span style="font-family:Calibri;">docker.domain.com.crt</span><span style="font-family:'宋体';">。</span></span></p> <p><span style="text-decoration:line-through;">新建<span style="font-family:Calibri;">ssl</span><span style="font-family:'宋体';">文件夹并将</span><span style="font-family:Calibri;">docker.domain.com.keydocker.domain.com.crt</span><span style="font-family:'宋体';">这两个文件移入</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">删除其他文件。</span></span></p> <h3><strong><span style="text-decoration:line-through;">配置私有仓库</span></strong></h3> <p><span style="text-decoration:line-through;">私有仓库默认的配置文件位于<span style="font-family:Calibri;">/etc/docker/registry/config.yml,</span><span style="font-family:'宋体';">我们先在本地编辑</span><span style="font-family:Calibri;">config.yml,</span><span style="font-family:'宋体';">之后挂载到容器中。</span></span></p> <p><span style="text-decoration:line-through;">version: 0.1</span></p> <p><span style="text-decoration:line-through;">log:</span></p> <p><span style="text-decoration:line-through;">accesslog:</span></p> <p><span style="text-decoration:line-through;"> disabled: true</span></p> <p><span style="text-decoration:line-through;">level: debug</span></p> <p><span style="text-decoration:line-through;">formatter: text</span></p> <p><span style="text-decoration:line-through;">fields:</span></p> <p><span style="text-decoration:line-through;"> service: registry</span></p> <p><span style="text-decoration:line-through;"> environment: staging</span></p> <p><span style="text-decoration:line-through;">storage:</span></p> <p><span style="text-decoration:line-through;">delete:</span></p> <p><span style="text-decoration:line-through;"> enabled: true</span></p> <p><span style="text-decoration:line-through;">cache:</span></p> <p><span style="text-decoration:line-through;"> blobdescriptor: inmemory</span></p> <p><span style="text-decoration:line-through;">filesystem:</span></p> <p><span style="text-decoration:line-through;"> rootdirectory: /var/lib/registry</span></p> <p><span style="text-decoration:line-through;">auth:</span></p> <p><span style="text-decoration:line-through;">htpasswd:</span></p> <p><span style="text-decoration:line-through;"> realm: basic-realm</span></p> <p><span style="text-decoration:line-through;"> path: /etc/docker/registry/auth/nginx.htpasswd</span></p> <p><span style="text-decoration:line-through;">http:</span></p> <p><span style="text-decoration:line-through;">addr: :443</span></p> <p><span style="text-decoration:line-through;">host: https://docker.domain.com</span></p> <p><span style="text-decoration:line-through;">headers:</span></p> <p><span style="text-decoration:line-through;"> X-Content-Type-Options: [nosniff]</span></p> <p><span style="text-decoration:line-through;">http2:</span></p> <p><span style="text-decoration:line-through;"> disabled: false</span></p> <p><span style="text-decoration:line-through;">tls:</span></p> <p><span style="text-decoration:line-through;"> certificate: /etc/docker/registry/ssl/docker.domain.com.crt</span></p> <p><span style="text-decoration:line-through;"> key: /etc/docker/registry/ssl/docker.domain.com.key</span></p> <p><span style="text-decoration:line-through;">health:</span></p> <p><span style="text-decoration:line-through;">storagedriver:</span></p> <p><span style="text-decoration:line-through;"> enabled: true</span></p> <p><span style="text-decoration:line-through;"> interval: 10s</span></p> <p><span style="text-decoration:line-through;">threshold: 3</span></p> <h3><strong><span style="text-decoration:line-through;">生成 <span style="font-family:Calibri;">http </span><span style="font-family:'宋体';">认证文件</span></span></strong></h3> <p><span style="text-decoration:line-through;">$ mkdir auth</span></p> <p><span style="text-decoration:line-through;">$ docker run --rm \</span></p> <p><span style="text-decoration:line-through;"> --entrypoint htpasswd \</span></p> <p><span style="text-decoration:line-through;"> registry \</span></p> <p><span style="text-decoration:line-through;"> -Bbn username password > auth/nginx.htpasswd</span></p> <p><span style="text-decoration:line-through;">将上面的<span style="font-family:Calibri;">usernamepassword</span><span style="font-family:'宋体';">替换为你自己的用户名和密码。</span></span></p> <h3><strong><span style="text-decoration:line-through;">编辑<span style="font-family:Calibri;">docker-compose.yml</span></span></strong></h3> <p><span style="text-decoration:line-through;">version: '3'</span></p> <p><span style="text-decoration:line-through;">services:</span></p> <p><span style="text-decoration:line-through;">registry:</span></p> <p><span style="text-decoration:line-through;"> image: registry</span></p> <p><span style="text-decoration:line-through;"> ports:</span></p> <p><span style="text-decoration:line-through;">- "443:443"</span></p> <p><span style="text-decoration:line-through;"> volumes:</span></p> <p><span style="text-decoration:line-through;">- ./:/etc/docker/registry</span></p> <p><span style="text-decoration:line-through;">- registry-data:/var/lib/registry</span></p> <p><span style="text-decoration:line-through;">volumes:</span></p> <p><span style="text-decoration:line-through;">registry-data:</span></p> <h3><strong><span style="text-decoration:line-through;">修改 <span style="font-family:Calibri;">hosts</span></span></strong></h3> <p><span style="text-decoration:line-through;">编辑<span style="font-family:Calibri;">/etc/hosts </span></span></p> <p><span style="text-decoration:line-through;">docker.domain.com 127.0.0.1</span></p> <h3><strong><span style="text-decoration:line-through;">启动</span></strong></h3> <p><span style="text-decoration:line-through;">$ docker-compose up -d</span></p> <p><span style="text-decoration:line-through;">这样我们就搭建好了一个具有权限认证、<span style="font-family:Calibri;">TLS </span><span style="font-family:'宋体';">的私有仓库</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">接下来我们测试其功能是否正常。</span></span></p> <h3><strong><span style="text-decoration:line-through;">测试私有仓库功能</span></strong></h3> <p><span style="text-decoration:line-through;">登录到私有仓库。</span></p> <p><span style="text-decoration:line-through;">$ docker login docker.domain.com</span></p> <p><span style="text-decoration:line-through;"> </span></p> <p><span style="text-decoration:line-through;">尝试推送、拉取镜像。</span></p> <p><span style="text-decoration:line-through;">$ docker pull ubuntu:17.10</span></p> <p><span style="text-decoration:line-through;">$ docker tag ubuntu:17.10 docker.domain.com/username/ubuntu:17.10</span></p> <p><span style="text-decoration:line-through;">$ docker push docker.domain.com/username/ubuntu:17.10</span></p> <p><span style="text-decoration:line-through;">$ docker image rm docker.domain.com/username/ubuntu:17.10</span></p> <p><span style="text-decoration:line-through;">$ docker pull docker.domain.com/username/ubuntu:17.10</span></p> <p><span style="text-decoration:line-through;"> </span></p> <p><span style="text-decoration:line-through;">如果我们退出登录<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">尝试推送镜像。</span></span></p> <p><span style="text-decoration:line-through;">$ docker logout docker.domain.com</span></p> <p><span style="text-decoration:line-through;">$ docker push docker.domain.com/username/ubuntu:17.10</span></p> <p><span style="text-decoration:line-through;">no basic auth credentials</span></p> <p><span style="text-decoration:line-through;">发现会提示没有登录<span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">不能将镜像推送到私有仓库中。</span></span></p> <h3><strong><span style="text-decoration:line-through;">注意事项</span></strong></h3> <p><span style="text-decoration:line-through;">如果你本机占用了<span style="font-family:Calibri;">443</span><span style="font-family:'宋体';">端口</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">你可以配置 </span><span style="font-family:Calibri;">Nginx </span><span style="font-family:'宋体';">代理</span><span style="font-family:Calibri;">,</span><span style="font-family:'宋体';">这里不再赘述。</span></span></p> </div> <p>转载于:https://www.cnblogs.com/shoubituling/p/9113411.html</p> </div> </div> </div> </div> </div> <!--PC和WAP自适应版--> <div id="SOHUCS" sid="1280098193417191424"></div> <script type="text/javascript" src="/views/front/js/chanyan.js"></script> <!-- 文章页-底部 动态广告位 --> <div class="youdao-fixed-ad" id="detail_ad_bottom"></div> </div> <div class="col-md-3"> <div class="row" id="ad"> <!-- 文章页-右侧1 动态广告位 --> <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_1"> </div> </div> <!-- 文章页-右侧2 动态广告位 --> <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_2"></div> </div> <!-- 文章页-右侧3 动态广告位 --> <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_3"></div> </div> </div> </div> </div> </div> </div> <div class="container"> <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(Docker 安装、镜像、dockerfile、容器、仓库)</h4> <div id="paradigm-article-related"> <div class="recommend-post mb30"> <ul class="widget-links"> <li><a href="/article/1835512920797179904.htm" title="element实现动态路由+面包屑" target="_blank">element实现动态路由+面包屑</a> <span class="text-muted">软件技术NINI</span> <a class="tag" taget="_blank" href="/search/vue%E6%A1%88%E4%BE%8B/1.htm">vue案例</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>el-breadcrumb是ElementUI组件库中的一个面包屑导航组件,它用于显示当前页面的路径,帮助用户快速理解和导航到应用的各个部分。在Vue.js项目中,如果你已经安装了ElementUI,就可以很方便地使用el-breadcrumb组件。以下是一个基本的使用示例:安装ElementUI(如果你还没有安装的话):你可以通过npm或yarn来安装ElementUI。bash复制代码npmi</div> </li> <li><a href="/article/1835511912843014144.htm" title="理解Gunicorn:Python WSGI服务器的基石" target="_blank">理解Gunicorn:Python WSGI服务器的基石</a> <span class="text-muted">范范0825</span> <a class="tag" taget="_blank" href="/search/ipython/1.htm">ipython</a><a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/%E8%BF%90%E7%BB%B4/1.htm">运维</a> <div>理解Gunicorn:PythonWSGI服务器的基石介绍Gunicorn,全称GreenUnicorn,是一个为PythonWSGI(WebServerGatewayInterface)应用设计的高效、轻量级HTTP服务器。作为PythonWeb应用部署的常用工具,Gunicorn以其高性能和易用性著称。本文将介绍Gunicorn的基本概念、安装和配置,帮助初学者快速上手。1.什么是Gunico</div> </li> <li><a href="/article/1835509643619692544.htm" title="如何在 Fork 的 GitHub 项目中保留自己的修改并同步上游更新?github_fork_update" target="_blank">如何在 Fork 的 GitHub 项目中保留自己的修改并同步上游更新?github_fork_update</a> <span class="text-muted">iBaoxing</span> <a class="tag" taget="_blank" href="/search/github/1.htm">github</a> <div>如何在Fork的GitHub项目中保留自己的修改并同步上游更新?在GitHub上Fork了一个项目后,你可能会对项目进行一些修改,同时原作者也在不断更新。如果想要在保留自己修改的基础上,同步原作者的最新更新,很多人会不知所措。本文将详细讲解如何在不丢失自己改动的情况下,将上游仓库的更新合并到自己的仓库中。问题描述假设你在GitHub上Fork了一个项目,并基于该项目做了一些修改,随后你发现原作者对</div> </li> <li><a href="/article/1835506869838376960.htm" title="Python数据分析与可视化实战指南" target="_blank">Python数据分析与可视化实战指南</a> <span class="text-muted">William数据分析</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE/1.htm">数据</a> <div>在数据驱动的时代,Python因其简洁的语法、强大的库生态系统以及活跃的社区,成为了数据分析与可视化的首选语言。本文将通过一个详细的案例,带领大家学习如何使用Python进行数据分析,并通过可视化来直观呈现分析结果。一、环境准备1.1安装必要库在开始数据分析和可视化之前,我们需要安装一些常用的库。主要包括pandas、numpy、matplotlib和seaborn等。这些库分别用于数据处理、数学</div> </li> <li><a href="/article/1835505858444881920.htm" title="git常用命令笔记" target="_blank">git常用命令笔记</a> <span class="text-muted">咩酱-小羊</span> <a class="tag" taget="_blank" href="/search/git/1.htm">git</a><a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AE%B0/1.htm">笔记</a> <div>###用习惯了idea总是不记得git的一些常见命令,需要用到的时候总是担心旁边站了人~~~记个笔记@_@,告诉自己看笔记不丢人初始化初始化一个新的Git仓库gitinit配置配置用户信息gitconfig--globaluser.name"YourName"gitconfig--globaluser.email"youremail@example.com"基本操作克隆远程仓库gitclone查看</div> </li> <li><a href="/article/1835504596898902016.htm" title="linux sdl windows.h,Windows下的SDL安装" target="_blank">linux sdl windows.h,Windows下的SDL安装</a> <span class="text-muted">奔跑吧linux内核</span> <a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/sdl/1.htm">sdl</a><a class="tag" taget="_blank" href="/search/windows.h/1.htm">windows.h</a> <div>首先你要下载并安装SDL开发包。如果装在C盘下,路径为C:\SDL1.2.5如果在WINDOWS下。你可以按以下步骤:1.打开VC++,点击"Tools",Options2,点击directories选项3.选择"Includefiles"增加一个新的路径。"C:\SDL1.2.5\include"4,现在选择"Libaryfiles“增加"C:\SDL1.2.5\lib"现在你可以开始编写你的第</div> </li> <li><a href="/article/1835504217729626112.htm" title="Python教程:一文了解使用Python处理XPath" target="_blank">Python教程:一文了解使用Python处理XPath</a> <span class="text-muted">旦莫</span> <a class="tag" taget="_blank" href="/search/Python%E8%BF%9B%E9%98%B6/1.htm">Python进阶</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>目录1.环境准备1.1安装lxml1.2验证安装2.XPath基础2.1什么是XPath?2.2XPath语法2.3示例XML文档3.使用lxml解析XML3.1解析XML文档3.2查看解析结果4.XPath查询4.1基本路径查询4.2使用属性查询4.3查询多个节点5.XPath的高级用法5.1使用逻辑运算符5.2使用函数6.实战案例6.1从网页抓取数据6.1.1安装Requests库6.1.2代</div> </li> <li><a href="/article/1835502578050363392.htm" title="PHP环境搭建详细教程" target="_blank">PHP环境搭建详细教程</a> <span class="text-muted">好看资源平台</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/php/1.htm">php</a> <div>PHP是一个流行的服务器端脚本语言,广泛用于Web开发。为了使PHP能够在本地或服务器上运行,我们需要搭建一个合适的PHP环境。本教程将结合最新资料,介绍在不同操作系统上搭建PHP开发环境的多种方法,包括Windows、macOS和Linux系统的安装步骤,以及本地和Docker环境的配置。1.PHP环境搭建概述PHP环境的搭建主要分为以下几类:集成开发环境:例如XAMPP、WAMP、MAMP,这</div> </li> <li><a href="/article/1835502578511736832.htm" title="下载github patch到本地" target="_blank">下载github patch到本地</a> <span class="text-muted">小米人er</span> <a class="tag" taget="_blank" href="/search/%E6%88%91%E7%9A%84%E5%8D%9A%E5%AE%A2/1.htm">我的博客</a><a class="tag" taget="_blank" href="/search/git/1.htm">git</a><a class="tag" taget="_blank" href="/search/patch/1.htm">patch</a> <div>以下是几种从GitHub上下载以.patch结尾的补丁文件的方法:通过浏览器直接下载打开包含该.patch文件的GitHub仓库。在仓库的文件列表中找到对应的.patch文件。点击该文件,浏览器会显示文件的内容,在页面的右上角通常会有一个“Raw”按钮,点击它可以获取原始文件内容。然后在浏览器中使用快捷键(如Ctrl+S或者Command+S)将原始文件保存到本地,选择保存的文件名并确保后缀为.p</div> </li> <li><a href="/article/1835499052125483008.htm" title="Git常用命令-修改远程仓库地址" target="_blank">Git常用命令-修改远程仓库地址</a> <span class="text-muted">猿大师</span> <a class="tag" taget="_blank" href="/search/Linux/1.htm">Linux</a><a class="tag" taget="_blank" href="/search/Java/1.htm">Java</a><a class="tag" taget="_blank" href="/search/git/1.htm">git</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>查看远程仓库地址gitremote-v返回结果originhttps://git.coding.net/*****.git(fetch)originhttps://git.coding.net/*****.git(push)修改远程仓库地址gitremoteset-urloriginhttps://git.coding.net/*****.git先删除后增加远程仓库地址gitremotermori</div> </li> <li><a href="/article/1835497665337585664.htm" title="使用LLaVa和Ollama实现多模态RAG示例" target="_blank">使用LLaVa和Ollama实现多模态RAG示例</a> <span class="text-muted">llzwxh888</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>本文将详细介绍如何使用LLaVa和Ollama实现多模态RAG(检索增强生成),通过提取图像中的结构化数据、生成图像字幕等功能来展示这一技术的强大之处。安装环境首先,您需要安装以下依赖包:!pipinstallllama-index-multi-modal-llms-ollama!pipinstallllama-index-readers-file!pipinstallunstructured!p</div> </li> <li><a href="/article/1835496402042580992.htm" title="GitHub上克隆项目" target="_blank">GitHub上克隆项目</a> <span class="text-muted">bigbig猩猩</span> <a class="tag" taget="_blank" href="/search/github/1.htm">github</a> <div>从GitHub上克隆项目是一个简单且直接的过程,它允许你将远程仓库中的项目复制到你的本地计算机上,以便进行进一步的开发、测试或学习。以下是一个详细的步骤指南,帮助你从GitHub上克隆项目。一、准备工作1.安装Git在克隆GitHub项目之前,你需要在你的计算机上安装Git工具。Git是一个开源的分布式版本控制系统,用于跟踪和管理代码变更。你可以从Git的官方网站(https://git-scm.</div> </li> <li><a href="/article/1835495770502033408.htm" title="Day17笔记-高阶函数" target="_blank">Day17笔记-高阶函数</a> <span class="text-muted">~在杰难逃~</span> <a class="tag" taget="_blank" href="/search/Python/1.htm">Python</a><a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AE%B0/1.htm">笔记</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/pycharm/1.htm">pycharm</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/1.htm">数据分析</a> <div>高阶函数【重点掌握】函数的本质:函数是一个变量,函数名是一个变量名,一个函数可以作为另一个函数的参数或返回值使用如果A函数作为B函数的参数,B函数调用完成之后,会得到一个结果,则B函数被称为高阶函数常用的高阶函数:map(),reduce(),filter(),sorted()1.map()map(func,iterable),返回值是一个iterator【容器,迭代器】func:函数iterab</div> </li> <li><a href="/article/1835491859351302144.htm" title="Python 实现图片裁剪(附代码) | Python工具" target="_blank">Python 实现图片裁剪(附代码) | Python工具</a> <span class="text-muted">剑客阿良_ALiang</span> <div>前言本文提供将图片按照自定义尺寸进行裁剪的工具方法,一如既往的实用主义。环境依赖ffmpeg环境安装,可以参考我的另一篇文章:windowsffmpeg安装部署_阿良的博客-CSDN博客本文主要使用到的不是ffmpeg,而是ffprobe也在上面这篇文章中的zip包中。ffmpy安装:pipinstallffmpy-ihttps://pypi.douban.com/simple代码不废话了,上代码</div> </li> <li><a href="/article/1835491101276991488.htm" title="数据仓库——维度表一致性" target="_blank">数据仓库——维度表一致性</a> <span class="text-muted">墨染丶eye</span> <a class="tag" taget="_blank" href="/search/%E8%83%8C%E8%AF%B5/1.htm">背诵</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E4%BB%93%E5%BA%93/1.htm">数据仓库</a> <div>数据仓库基础笔记思维导图已经整理完毕,完整连接为:数据仓库基础知识笔记思维导图维度一致性问题从逻辑层面来看,当一系列星型模型共享一组公共维度时,所涉及的维度称为一致性维度。当维度表存在不一致时,短期的成功难以弥补长期的错误。维度时确保不同过程中信息集成起来实现横向钻取货活动的关键。造成横向钻取失败的原因维度结构的差别,因为维度的差别,分析工作涉及的领域从简单到复杂,但是都是通过复杂的报表来弥补设计</div> </li> <li><a href="/article/1835490712716668928.htm" title="第六集如何安装CentOS7.0,3分钟学会centos7安装教程" target="_blank">第六集如何安装CentOS7.0,3分钟学会centos7安装教程</a> <span class="text-muted">date分享</span> <div>从光盘引导系统按回车键继续进入引导程序安装界面,选择语言这里选择简体中文版点击继续选择桌面安装下面给系统分区选择磁盘,点击完成选择基本分区,点击加号swap分区,大小填内存的两倍在选择根分区,使用所有可用的磁盘空间选择文件系统ext4点击完成,点击开始安装设置root密码,点击完成设置普通用户和密码,点击完成整个过程持续八分钟左右根据个人配置不同,时间长短不同好,现在点击重启系统进入重启状态点击本</div> </li> <li><a href="/article/1835490218845761536.htm" title="Python爬虫解析工具之xpath使用详解" target="_blank">Python爬虫解析工具之xpath使用详解</a> <span class="text-muted">eqa11</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>文章目录Python爬虫解析工具之xpath使用详解一、引言二、环境准备1、插件安装2、依赖库安装三、xpath语法详解1、路径表达式2、通配符3、谓语4、常用函数四、xpath在Python代码中的使用1、文档树的创建2、使用xpath表达式3、获取元素内容和属性五、总结Python爬虫解析工具之xpath使用详解一、引言在Python爬虫开发中,数据提取是一个至关重要的环节。xpath作为一门</div> </li> <li><a href="/article/1835485429059645440.htm" title="docker" target="_blank">docker</a> <span class="text-muted">igotyback</span> <a class="tag" taget="_blank" href="/search/eureka/1.htm">eureka</a><a class="tag" taget="_blank" href="/search/%E4%BA%91%E5%8E%9F%E7%94%9F/1.htm">云原生</a> <div>Docker容器的文件系统是隔离的,但是可以通过挂载卷(Volumes)或绑定挂载(BindMounts)将宿主机的文件系统目录映射到容器内部。要查看Docker容器的映射路径,可以使用以下方法:查看容器配置:使用dockerinspect命令可以查看容器的详细配置信息,包括挂载的卷。例如:bashdockerinspect在输出的JSON格式中,查找"Mounts"部分,这里会列出所有的挂载信息</div> </li> <li><a href="/article/1835484293607026688.htm" title="【Git】常见命令(仅笔记)" target="_blank">【Git】常见命令(仅笔记)</a> <span class="text-muted">好想有猫猫</span> <a class="tag" taget="_blank" href="/search/Git/1.htm">Git</a><a class="tag" taget="_blank" href="/search/Linux%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/1.htm">Linux学习笔记</a><a class="tag" taget="_blank" href="/search/git/1.htm">git</a><a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AE%B0/1.htm">笔记</a><a class="tag" taget="_blank" href="/search/elasticsearch/1.htm">elasticsearch</a><a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/c%2B%2B/1.htm">c++</a> <div>文章目录创建/初始化本地仓库添加本地仓库配置项提交文件查看仓库状态回退仓库查看日志分支删除文件暂存工作区代码远程仓库使用`.gitigore`文件让git不追踪一些文件标签创建/初始化本地仓库gitinit添加本地仓库配置项gitconfig-l#以列表形式显示配置项gitconfiguser.name"ljh"#配置user.namegitconfiguser.email"123123@qq.c</div> </li> <li><a href="/article/1835479000600899584.htm" title="Linux MariaDB使用OpenSSL安装SSL证书" target="_blank">Linux MariaDB使用OpenSSL安装SSL证书</a> <span class="text-muted">Meta39</span> <a class="tag" taget="_blank" href="/search/MySQL/1.htm">MySQL</a><a class="tag" taget="_blank" href="/search/Oracle/1.htm">Oracle</a><a class="tag" taget="_blank" href="/search/MariaDB/1.htm">MariaDB</a><a class="tag" taget="_blank" href="/search/Linux/1.htm">Linux</a><a class="tag" taget="_blank" href="/search/Windows/1.htm">Windows</a><a class="tag" taget="_blank" href="/search/ssl/1.htm">ssl</a><a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/mariadb/1.htm">mariadb</a> <div>进入到证书存放目录,批量删除.pem证书警告:确保已经进入到证书存放目录find.-typef-iname\*.pem-delete查看是否安装OpenSSLopensslversion没有则安装yuminstallopensslopenssl-devel开启SSL编辑/etc/my.cnf文件(没有的话就创建,但是要注意,在/etc/my.cnf.d/server.cnf配置了datadir的,</div> </li> <li><a href="/article/1835476984034062336.htm" title="【六】阿伟开始搭建Kafka学习环境" target="_blank">【六】阿伟开始搭建Kafka学习环境</a> <span class="text-muted">能源恒观</span> <a class="tag" taget="_blank" href="/search/%E4%B8%AD%E9%97%B4%E4%BB%B6/1.htm">中间件</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/kafka/1.htm">kafka</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a> <div>阿伟开始搭建Kafka学习环境概述上一篇文章阿伟学习了Kafka的核心概念,并且把市面上流行的消息中间件特性进行了梳理和对比,方便大家在学习过程中进行对比学习,最后梳理了一些Kafka使用中经常遇到的Kafka难题以及解决思路,经过上一篇的学习我相信大家对Kafka有了初步的认识,本篇将继续学习Kafka。一、安装和配置学习一项技术首先要搭建一套服务,而Kafka的运行主要需要部署jdk、zook</div> </li> <li><a href="/article/1835475216080400384.htm" title="openssl+keepalived安装部署" target="_blank">openssl+keepalived安装部署</a> <span class="text-muted">_小亦_</span> <a class="tag" taget="_blank" href="/search/%E9%A1%B9%E7%9B%AE%E9%83%A8%E7%BD%B2/1.htm">项目部署</a><a class="tag" taget="_blank" href="/search/keepalived/1.htm">keepalived</a><a class="tag" taget="_blank" href="/search/openssl/1.htm">openssl</a> <div>文章目录OpenSSL安装下载地址编译安装修改系统配置版本Keepalived安装下载地址安装遇到问题安装完成配置文件keepalived运行检查运行状态查看系统日志修改服务service重新加载systemd检查配置文件语法错误OpenSSL安装下载地址考虑到后面设备可能没法连接到外网,所以采用安装包的方式进行部署,下载地址:https://www.openssl.org/source/old/</div> </li> <li><a href="/article/1835471058648526848.htm" title="1分钟解决 -bash: mvn: command not found,在Centos 7中安装Maven" target="_blank">1分钟解决 -bash: mvn: command not found,在Centos 7中安装Maven</a> <span class="text-muted">Energet!c</span> <a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>1分钟解决-bash:mvn:commandnotfound,在Centos7中安装Maven检查Java环境1下载Maven2解压Maven3配置环境变量4验证安装5常见问题与注意事项6总结检查Java环境Maven依赖Java环境,请确保系统已经安装了Java并配置了环境变量。可以通过以下命令检查:java-version如果未安装,请先安装Java。1下载Maven从官网下载:前往Apach</div> </li> <li><a href="/article/1835469798838988800.htm" title="Python实现简单的机器学习算法" target="_blank">Python实现简单的机器学习算法</a> <span class="text-muted">master_chenchengg</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%8A%9E%E5%85%AC%E6%95%88%E7%8E%87/1.htm">办公效率</a><a class="tag" taget="_blank" href="/search/python%E5%BC%80%E5%8F%91/1.htm">python开发</a><a class="tag" taget="_blank" href="/search/IT/1.htm">IT</a> <div>Python实现简单的机器学习算法开篇:初探机器学习的奇妙之旅搭建环境:一切从安装开始必备工具箱第一步:安装Anaconda和JupyterNotebook小贴士:如何配置Python环境变量算法初体验:从零开始的Python机器学习线性回归:让数据说话数据准备:从哪里找数据编码实战:Python实现线性回归模型评估:如何判断模型好坏逻辑回归:从分类开始理论入门:什么是逻辑回归代码实现:使用skl</div> </li> <li><a href="/article/1835466929016500224.htm" title="但行好事,莫问前程" target="_blank">但行好事,莫问前程</a> <span class="text-muted">浅草拾光</span> <div>鸿星尔克被冲上了热搜,他可能做梦也没有想到自己的一个善举便迎来了他的春天。在这次河南救灾中很多明星企业都纷纷捐款,而一个快被人遗忘的品牌掏出了自己的家底。在自己年利润是亏损2.28亿的时候还大方的捐了五千万物资。热心的网友纷纷留言,大家都跑去直播间支持国货,去实体店买鞋子。以至于订单爆满,仓库清空。老板劝大家理性消费,大家反而更冲动。就是这样一种热情,这样一种情怀,感动了平凡的你我。大家都说华夏儿</div> </li> <li><a href="/article/1835465261080211456.htm" title="CentOS 7官方源停服,配置本机光盘yum源" target="_blank">CentOS 7官方源停服,配置本机光盘yum源</a> <span class="text-muted">码哝小鱼</span> <a class="tag" taget="_blank" href="/search/linux%E8%BF%90%E7%BB%B4/1.htm">linux运维</a><a class="tag" taget="_blank" href="/search/centos/1.htm">centos</a><a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/%E8%BF%90%E7%BB%B4/1.htm">运维</a> <div>1、挂载系统光盘mkdir/mnt/isomount-oloop/tools/CentOS-7-x86_64-DVD-1810.iso/mnt/isocd/mnt/iso/Packages/rpm-ivh/mnt/iso/Packages/yum-utils-1.1.31-50.el7.noarch.rpm(图形界面安装,默契已安装)如安装yum-utils依赖错误,按提示安装依赖包rpm-ivh</div> </li> <li><a href="/article/1835463622344667136.htm" title="基于Python给出的PDF文档转Markdown文档的方法" target="_blank">基于Python给出的PDF文档转Markdown文档的方法</a> <span class="text-muted">程序媛了了</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/pdf/1.htm">pdf</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>注:网上有很多将Markdown文档转为PDF文档的方法,但是却很少有将PDF文档转为Markdown文档的方法。就算有,比如某些网站声称可以将PDF文档转为Markdown文档,尝试过,不太符合自己的要求,而且无法保证文档没有泄露风险。于是本人为了解决这个问题,借助GPT(能使用GPT镜像或者有条件直接使用GPT的,反正能调用GPT接口就行)生成Python代码来完成这个功能。笔记、代码难免存在</div> </li> <li><a href="/article/1835457442260021248.htm" title="ArrayList 源码解析" target="_blank">ArrayList 源码解析</a> <span class="text-muted">程序猿进阶</span> <a class="tag" taget="_blank" href="/search/Java%E5%9F%BA%E7%A1%80/1.htm">Java基础</a><a class="tag" taget="_blank" href="/search/ArrayList/1.htm">ArrayList</a><a class="tag" taget="_blank" href="/search/List/1.htm">List</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a><a class="tag" taget="_blank" href="/search/%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96/1.htm">性能优化</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1/1.htm">架构设计</a><a class="tag" taget="_blank" href="/search/idea/1.htm">idea</a> <div>ArrayList是Java集合框架中的一个动态数组实现,提供了可变大小的数组功能。它继承自AbstractList并实现了List接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入null元素,底层通过数组实现。除该类未实现同步外,其余跟Vector大致相同。每个ArrayList都有一个容量capacity,表示底层数组的实际大小,容器内存储元素的个数不能多于当前容量。当向容器中添</div> </li> <li><a href="/article/1835449123252301824.htm" title="Python入门之Lesson2:Python基础语法" target="_blank">Python入门之Lesson2:Python基础语法</a> <span class="text-muted">小熊同学哦</span> <a class="tag" taget="_blank" href="/search/Python%E5%85%A5%E9%97%A8%E8%AF%BE%E7%A8%8B/1.htm">Python入门课程</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/1.htm">数据结构</a><a class="tag" taget="_blank" href="/search/%E9%9D%92%E5%B0%91%E5%B9%B4%E7%BC%96%E7%A8%8B/1.htm">青少年编程</a> <div>目录前言一.介绍1.变量和数据类型2.常见运算符3.输入输出4.条件语句5.循环结构二.练习三.总结前言欢迎来到《Python入门》系列博客的第二课。在上一课中,我们了解了Python的安装及运行环境的配置。在这一课中,我们将深入学习Python的基础语法,这是编写Python代码的根基。通过本节内容的学习,你将掌握变量、数据类型、运算符、输入输出、条件语句等Python编程的基础知识。一.介绍1</div> </li> <li><a href="/article/1835448111909138432.htm" title="react-intl——react国际化使用方案" target="_blank">react-intl——react国际化使用方案</a> <span class="text-muted">苹果酱0567</span> <a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95%E9%A2%98%E6%B1%87%E6%80%BB%E4%B8%8E%E8%A7%A3%E6%9E%90/1.htm">面试题汇总与解析</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/%E4%B8%AD%E9%97%B4%E4%BB%B6/1.htm">中间件</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a> <div>国际化介绍i18n:internationalization国家化简称,首字母+首尾字母间隔的字母个数+尾字母,类似的还有k8s(Kubernetes)React-intl是React中最受欢迎的库。使用步骤安装#usenpmnpminstallreact-intl-D#useyarn项目入口文件配置//index.tsximportReactfrom"react";importReactDOMf</div> </li> <li><a href="/article/33.htm" title="Spring的注解积累" target="_blank">Spring的注解积累</a> <span class="text-muted">yijiesuifeng</span> <a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/%E6%B3%A8%E8%A7%A3/1.htm">注解</a> <div>用注解来向Spring容器注册Bean。   需要在applicationContext.xml中注册: <context:component-scan base-package=”pagkage1[,pagkage2,…,pagkageN]”/>。 如:在base-package指明一个包    <context:component-sc</div> </li> <li><a href="/article/160.htm" title="传感器" target="_blank">传感器</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/%E4%BC%A0%E6%84%9F%E5%99%A8/1.htm">传感器</a> <div>android传感器的作用主要就是来获取数据,根据得到的数据来触发某种事件   下面就以重力传感器为例;   1,在onCreate中获得传感器服务   private SensorManager sm;// 获得系统的服务 private Sensor sensor;// 创建传感器实例 @Override protected void </div> </li> <li><a href="/article/287.htm" title="[光磁与探测]金吕玉衣的意义" target="_blank">[光磁与探测]金吕玉衣的意义</a> <span class="text-muted">comsci</span> <div>      这是一个古代人的秘密:现在告诉大家       信不信由你们:       穿上金律玉衣的人,如果处于灵魂出窍的状态,可以飞到宇宙中去看星星       这就是为什么古代</div> </li> <li><a href="/article/414.htm" title="精简的反序打印某个数" target="_blank">精简的反序打印某个数</a> <span class="text-muted">沐刃青蛟</span> <a class="tag" taget="_blank" href="/search/%E6%89%93%E5%8D%B0/1.htm">打印</a> <div>以前看到一些让求反序打印某个数的程序。 比如:输入123,输出321。   记得以前是告诉你是几位数的,当时就抓耳挠腮,完全没有思路。   似乎最后是用到%和/方法解决的。   而今突然想到一个简短的方法,就可以实现任意位数的反序打印(但是如果是首位数或者尾位数为0时就没有打印出来了)   代码如下: long num, num1=0;</div> </li> <li><a href="/article/541.htm" title="PHP:6种方法获取文件的扩展名" target="_blank">PHP:6种方法获取文件的扩展名</a> <span class="text-muted">IT独行者</span> <a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a><a class="tag" taget="_blank" href="/search/%E6%89%A9%E5%B1%95%E5%90%8D/1.htm">扩展名</a> <div>  PHP:6种方法获取文件的扩展名   1、字符串查找和截取的方法   1 $extension = substr ( strrchr ( $file ,  '.' ), 1); 2、字符串查找和截取的方法二   1 $extension = substr </div> </li> <li><a href="/article/668.htm" title="面试111" target="_blank">面试111</a> <span class="text-muted">文强chu</span> <a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a> <div> 1事务隔离级别有那些 ,事务特性是什么(问到一次) 2 spring aop 如何管理事务的,如何实现的。动态代理如何实现,jdk怎么实现动态代理的,ioc是怎么实现的,spring是单例还是多例,有那些初始化bean的方式,各有什么区别(经常问) 3 struts默认提供了那些拦截器 (一次) 4 过滤器和拦截器的区别 (频率也挺高) 5 final,finally final</div> </li> <li><a href="/article/795.htm" title="XML的四种解析方式" target="_blank">XML的四种解析方式</a> <span class="text-muted">小桔子</span> <a class="tag" taget="_blank" href="/search/dom/1.htm">dom</a><a class="tag" taget="_blank" href="/search/jdom/1.htm">jdom</a><a class="tag" taget="_blank" href="/search/dom4j/1.htm">dom4j</a><a class="tag" taget="_blank" href="/search/sax/1.htm">sax</a> <div>在平时工作中,难免会遇到把 XML 作为数据存储格式。面对目前种类繁多的解决方案,哪个最适合我们呢?在这篇文章中,我对这四种主流方案做一个不完全评测,仅仅针对遍历 XML 这块来测试,因为遍历 XML 是工作中使用最多的(至少我认为)。   预 备   测试环境:   AMD 毒龙1.4G OC 1.5G、256M DDR333、Windows2000 Server </div> </li> <li><a href="/article/922.htm" title="wordpress中常见的操作" target="_blank">wordpress中常见的操作</a> <span class="text-muted">aichenglong</span> <a class="tag" taget="_blank" href="/search/%E4%B8%AD%E6%96%87%E6%B3%A8%E5%86%8C/1.htm">中文注册</a><a class="tag" taget="_blank" href="/search/wordpress/1.htm">wordpress</a><a class="tag" taget="_blank" href="/search/%E7%A7%BB%E9%99%A4%E8%8F%9C%E5%8D%95/1.htm">移除菜单</a> <div>1 wordpress中使用中文名注册解决办法   1)使用插件   2)修改wp源代码      进入到wp-include/formatting.php文件中找到       function sanitize_user( $username, $strict = false </div> </li> <li><a href="/article/1049.htm" title="小飞飞学管理-1" target="_blank">小飞飞学管理-1</a> <span class="text-muted">alafqq</span> <a class="tag" taget="_blank" href="/search/%E7%AE%A1%E7%90%86/1.htm">管理</a> <div>项目管理的下午题,其实就在提出问题(挑刺),分析问题,解决问题。 今天我随意看下10年上半年的第一题。主要就是项目经理的提拨和培养。 结合我自己经历写下心得 对于公司选拔和培养项目经理的制度有什么毛病呢? 1,公司考察,选拔项目经理,只关注技术能力,而很少或没有关注管理方面的经验,能力。 2,公司对项目经理缺乏必要的项目管理知识和技能方面的培训。 3,公司对项目经理的工作缺乏进行指</div> </li> <li><a href="/article/1176.htm" title="IO输入输出部分探讨" target="_blank">IO输入输出部分探讨</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/IO/1.htm">IO</a> <div>  //文件处理  在处理文件输入输出时要引入java.IO这个包; /* 1,运用File类对文件目录和属性进行操作 2,理解流,理解输入输出流的概念 3,使用字节/符流对文件进行读/写操作 4,了解标准的I/O 5,了解对象序列化 */   //1,运用File类对文件目录和属性进行操作   //在工程中线创建一个text.txt</div> </li> <li><a href="/article/1303.htm" title="getElementById的用法" target="_blank">getElementById的用法</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/element/1.htm">element</a> <div>        getElementById是通过Id来设置/返回HTML标签的属性及调用其事件与方法。用这个方法基本上可以控制页面所有标签,条件很简单,就是给每个标签分配一个ID号。        返回具有指定ID属性值的第一个对象的一个引用。        语法: &n</div> </li> <li><a href="/article/1430.htm" title="励志经典语录" target="_blank">励志经典语录</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/%E5%8A%B1%E5%BF%97/1.htm">励志</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E7%94%9F/1.htm">人生</a> <div>经典语录1:   哈佛有一个著名的理论:人的差别在于业余时间,而一个人的命运决定于晚上8点到10点之间。每晚抽出2个小时的时间用来阅读、进修、思考或参加有意的演讲、讨论,你会发现,你的人生正在发生改变,坚持数年之后,成功会向你招手。不要每天抱着QQ/MSN/游戏/电影/肥皂剧……奋斗到12点都舍不得休息,看就看一些励志的影视或者文章,不要当作消遣;学会思考人生,学会感悟人生</div> </li> <li><a href="/article/1557.htm" title="[MongoDB学习笔记三]MongoDB分片" target="_blank">[MongoDB学习笔记三]MongoDB分片</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/mongodb/1.htm">mongodb</a> <div>MongoDB的副本集(Replica Set)一方面解决了数据的备份和数据的可靠性问题,另一方面也提升了数据的读写性能。MongoDB分片(Sharding)则解决了数据的扩容问题,MongoDB作为云计算时代的分布式数据库,大容量数据存储,高效并发的数据存取,自动容错等是MongoDB的关键指标。 本篇介绍MongoDB的切片(Sharding)   1.何时需要分片 &nbs</div> </li> <li><a href="/article/1684.htm" title="【Spark八十三】BlockManager在Spark中的使用场景" target="_blank">【Spark八十三】BlockManager在Spark中的使用场景</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/manager/1.htm">manager</a> <div>1. Broadcast变量的存储,在HttpBroadcast类中可以知道 2. RDD通过CacheManager存储RDD中的数据,CacheManager也是通过BlockManager进行存储的 3. ShuffleMapTask得到的结果数据,是通过FileShuffleBlockManager进行管理的,而FileShuffleBlockManager最终也是使用BlockMan</div> </li> <li><a href="/article/1811.htm" title="yum方式部署zabbix" target="_blank">yum方式部署zabbix</a> <span class="text-muted">ronin47</span> <a class="tag" taget="_blank" href="/search/yum%E6%96%B9%E5%BC%8F%E9%83%A8%E7%BD%B2zabbix/1.htm">yum方式部署zabbix</a> <div>安装网络yum库#rpm -ivh http://repo.zabbix.com/zabbix/2.4/rhel/6/x86_64/zabbix-release-2.4-1.el6.noarch.rpm 通过yum装mysql和zabbix调用的插件还有agent代理#yum install zabbix-server-mysql zabbix-web-mysql mysql-</div> </li> <li><a href="/article/1938.htm" title="Hibernate4和MySQL5.5自动创建表失败问题解决方法" target="_blank">Hibernate4和MySQL5.5自动创建表失败问题解决方法</a> <span class="text-muted">byalias</span> <a class="tag" taget="_blank" href="/search/J2EE/1.htm">J2EE</a><a class="tag" taget="_blank" href="/search/Hibernate4/1.htm">Hibernate4</a> <div>今天初学Hibernate4,了解了使用Hibernate的过程。大体分为4个步骤: ①创建hibernate.cfg.xml文件 ②创建持久化对象 ③创建*.hbm.xml映射文件 ④编写hibernate相应代码 在第四步中,进行了单元测试,测试预期结果是hibernate自动帮助在数据库中创建数据表,结果JUnit单元测试没有问题,在控制台打印了创建数据表的SQL语句,但在数据库中</div> </li> <li><a href="/article/2065.htm" title="Netty源码学习-FrameDecoder" target="_blank">Netty源码学习-FrameDecoder</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/netty/1.htm">netty</a> <div>Netty 3.x的user guide里FrameDecoder的例子,有几个疑问: 1.文档说:FrameDecoder calls decode method with an internally maintained cumulative buffer whenever new data is received. 为什么每次有新数据到达时,都会调用decode方法? 2.Dec</div> </li> <li><a href="/article/2192.htm" title="SQL行列转换方法" target="_blank">SQL行列转换方法</a> <span class="text-muted">chicony</span> <a class="tag" taget="_blank" href="/search/%E8%A1%8C%E5%88%97%E8%BD%AC%E6%8D%A2/1.htm">行列转换</a> <div> create table tb(终端名称 varchar(10) , CEI分值 varchar(10) , 终端数量 int) insert into tb values('三星' , '0-5' , 74) insert into tb values('三星' , '10-15' , 83) insert into tb values('苹果' , '0-5' , 93) </div> </li> <li><a href="/article/2319.htm" title="中文编码测试" target="_blank">中文编码测试</a> <span class="text-muted">ctrain</span> <a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A0%81/1.htm">编码</a> <div>循环打印转换编码 String[] codes = { "iso-8859-1", "utf-8", "gbk", "unicode" }; for (int i = 0; i < codes.length; i++) { for (int j </div> </li> <li><a href="/article/2446.htm" title="hive 客户端查询报堆内存溢出解决方法" target="_blank">hive 客户端查询报堆内存溢出解决方法</a> <span class="text-muted">daizj</span> <a class="tag" taget="_blank" href="/search/hive/1.htm">hive</a><a class="tag" taget="_blank" href="/search/%E5%A0%86%E5%86%85%E5%AD%98%E6%BA%A2%E5%87%BA/1.htm">堆内存溢出</a> <div>hive> select * from t_test where ds=20150323 limit 2; OK Exception in thread "main" java.lang.OutOfMemoryError: Java heap space   问题原因: hive堆内存默认为256M   这个问题的解决方法为: 修改/us</div> </li> <li><a href="/article/2573.htm" title="人有多大懒,才有多大闲 (评论『卓有成效的程序员』)" target="_blank">人有多大懒,才有多大闲 (评论『卓有成效的程序员』)</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E5%91%98/1.htm">程序员</a> <div>  卓有成效的程序员给我的震撼很大,程序员作为特殊的群体,有的人可以这么懒,  懒到事情都交给机器去做 ,而有的人又可以那么勤奋,每天都孜孜不倦得做着重复单调的工作。   在看这本书之前,我属于勤奋的人,而看完这本书以后,我要努力变成懒惰的人。 不要在去庞大的开始菜单里面一项一项搜索自己的应用程序,也不要在自己的桌面上放置眼花缭乱的快捷图标</div> </li> <li><a href="/article/2700.htm" title="Eclipse简单有用的配置" target="_blank">Eclipse简单有用的配置</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/eclipse/1.htm">eclipse</a> <div>1、显示行号  Window -- Prefences -- General -- Editors -- Text Editors -- show line numbers   2、代码提示字符 Window ->Perferences,并依次展开 Java -> Editor -> Content Assist,最下面一栏 auto-Activation</div> </li> <li><a href="/article/2827.htm" title="在tomcat上面安装solr4.8.0全过程" target="_blank">在tomcat上面安装solr4.8.0全过程</a> <span class="text-muted">eksliang</span> <a class="tag" taget="_blank" href="/search/Solr/1.htm">Solr</a><a class="tag" taget="_blank" href="/search/solr4.0%E5%90%8E%E7%9A%84%E7%89%88%E6%9C%AC%E5%AE%89%E8%A3%85/1.htm">solr4.0后的版本安装</a><a class="tag" taget="_blank" href="/search/solr4.8.0%E5%AE%89%E8%A3%85/1.htm">solr4.8.0安装</a> <div>转载请出自出处: http://eksliang.iteye.com/blog/2096478       首先solr是一个基于java的web的应用,所以安装solr之前必须先安装JDK和tomcat,我这里就先省略安装tomcat和jdk了         第一步:当然是下载去官网上下载最新的solr版本,下载地址</div> </li> <li><a href="/article/2954.htm" title="Android APP通用型拒绝服务、漏洞分析报告" target="_blank">Android APP通用型拒绝服务、漏洞分析报告</a> <span class="text-muted">gg163</span> <a class="tag" taget="_blank" href="/search/%E6%BC%8F%E6%B4%9E/1.htm">漏洞</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/APP/1.htm">APP</a><a class="tag" taget="_blank" href="/search/%E5%88%86%E6%9E%90/1.htm">分析</a> <div>点评:记得曾经有段时间很多SRC平台被刷了大量APP本地拒绝服务漏洞,移动安全团队爱内测(ineice.com)发现了一个安卓客户端的通用型拒绝服务漏洞,来看看他们的详细分析吧。  0xr0ot和Xbalien交流所有可能导致应用拒绝服务的异常类型时,发现了一处通用的本地拒绝服务漏洞。该通用型本地拒绝服务可以造成大面积的app拒绝服务。  针对序列化对象而出现的拒绝服务主要</div> </li> <li><a href="/article/3081.htm" title="HoverTree项目已经实现分层" target="_blank">HoverTree项目已经实现分层</a> <span class="text-muted">hvt</span> <a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B/1.htm">编程</a><a class="tag" taget="_blank" href="/search/.net/1.htm">.net</a><a class="tag" taget="_blank" href="/search/Web/1.htm">Web</a><a class="tag" taget="_blank" href="/search/C%23/1.htm">C#</a><a class="tag" taget="_blank" href="/search/ASP.ENT/1.htm">ASP.ENT</a> <div>HoverTree项目已经初步实现分层,源代码已经上传到 http://hovertree.codeplex.com请到SOURCE CODE查看。在本地用SQL Server 2008 数据库测试成功。数据库和表请参考:http://keleyi.com/a/bjae/ue6stb42.htmHoverTree是一个ASP.NET 开源项目,希望对你学习ASP.NET或者C#语言有帮助,如果你对</div> </li> <li><a href="/article/3208.htm" title="Google Maps API v3: Remove Markers 移除标记" target="_blank">Google Maps API v3: Remove Markers 移除标记</a> <span class="text-muted">天梯梦</span> <a class="tag" taget="_blank" href="/search/google+maps+api/1.htm">google maps api</a> <div>Simply do the following:   I. Declare a global variable: var markersArray = [];   II. Define a function: function clearOverlays() { for (var i = 0; i < markersArray.length; i++ )</div> </li> <li><a href="/article/3335.htm" title="jQuery选择器总结" target="_blank">jQuery选择器总结</a> <span class="text-muted">lq38366</span> <a class="tag" taget="_blank" href="/search/jquery/1.htm">jquery</a><a class="tag" taget="_blank" href="/search/%E9%80%89%E6%8B%A9%E5%99%A8/1.htm">选择器</a> <div>  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40</div> </li> <li><a href="/article/3462.htm" title="基础数据结构和算法六:Quick sort" target="_blank">基础数据结构和算法六:Quick sort</a> <span class="text-muted">sunwinner</span> <a class="tag" taget="_blank" href="/search/Algorithm/1.htm">Algorithm</a><a class="tag" taget="_blank" href="/search/Quicksort/1.htm">Quicksort</a> <div>Quick sort is probably used more widely than any other. It is popular because it is not difficult to implement, works well for a variety of different kinds of input data, and is substantially faster t</div> </li> <li><a href="/article/3589.htm" title="如何让Flash不遮挡HTML div元素的技巧_HTML/Xhtml_网页制作" target="_blank">如何让Flash不遮挡HTML div元素的技巧_HTML/Xhtml_网页制作</a> <span class="text-muted">刘星宇</span> <a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/Web/1.htm">Web</a> <div>今天在写一个flash广告代码的时候,因为flash自带的链接,容易被当成弹出广告,所以做了一个div层放到flash上面,这样链接都是a触发的不会被拦截,但发现flash一直处于div层上面,原来flash需要加个参数才可以。 让flash置于DIV层之下的方法,让flash不挡住飘浮层或下拉菜单,让Flash不档住浮动对象或层的关键参数:wmode=opaque。 方法如下: </div> </li> <li><a href="/article/3716.htm" title="Mybatis实用Mapper SQL汇总示例" target="_blank">Mybatis实用Mapper SQL汇总示例</a> <span class="text-muted">wdmcygah</span> <a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a><a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a><a class="tag" taget="_blank" href="/search/mybatis/1.htm">mybatis</a><a class="tag" taget="_blank" href="/search/%E5%AE%9E%E7%94%A8/1.htm">实用</a> <div>Mybatis作为一个非常好用的持久层框架,相关资料真的是少得可怜,所幸的是官方文档还算详细。本博文主要列举一些个人感觉比较常用的场景及相应的Mapper SQL写法,希望能够对大家有所帮助。 不少持久层框架对动态SQL的支持不足,在SQL需要动态拼接时非常苦恼,而Mybatis很好地解决了这个问题,算是框架的一大亮点。对于常见的场景,例如:批量插入/更新/删除,模糊查询,多条件查询,联表查询,</div> </li> </ul> </div> </div> </div> <div> <div class="container"> <div class="indexes"> <strong>按字母分类:</strong> <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a> </div> </div> </div> <footer id="footer" class="mb30 mt30"> <div class="container"> <div class="footBglm"> <a target="_blank" href="/">首页</a> - <a target="_blank" href="/custom/about.htm">关于我们</a> - <a target="_blank" href="/search/Java/1.htm">站内搜索</a> - <a target="_blank" href="/sitemap.txt">Sitemap</a> - <a target="_blank" href="/custom/delete.htm">侵权投诉</a> </div> <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved. <!-- <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>--> </div> </div> </footer> <!-- 代码高亮 --> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script> <link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/> <script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script> </body> </html>