《docker实践(1) 入门和springBoot实践部署》

《docker实践(2)常用命令和DockerFile详解》

《docker实践(3) 仓库registry和Nexus3作为私有镜像仓库 容器镜像原理和容器仓库registry详解》


一、 Docker镜像image原理


Docker Image 就是一个只读的文件,作为创建 Docker Container 的模板。镜像是容器的基石,容器基于镜像启动,镜像就像是容器的源代码,保存了用于容器启动的各种条件。

Docker 支持通过扩展现有镜像,继而创建新的镜像。实际上,Docker Hub 中 99% 的镜像都是通过在 base image 中安装和配置需要的软件构建出来的。

nexus3 手动删除镜像 nexus镜像仓库_docker

Docker Image 是一个层叠的只读文件系统,结构如下:

  • bootfs(引导文件系统):与 Linux Kernel 交互的引导系统。
  • rootfs(root 文件系统):根文件系统,即 base image,可以是一种或多种操作系统,如:Ubuntu 或 CentOS,rootfs 永远是只读状态。
  • unionFS(联合文件系统):即所有 base image 之上的文件系统。Docker 应用了 union mount(联合加载技术),一次可以加载多个只读文件系统到 rootfs 之上,从外面看到的只是一个文件系统。union mount 将各层文件系统叠加到一起,使最终呈现出来的文件系统包含了所有底层文件系统和目录,这样的文件系统就是镜像。

一个镜像可以放到另一个镜像的顶部,位于下边的镜像叫做父镜像,依次类推,最底部的镜像叫做 base image,指的就是 rootfs,即 Ubuntu 或 CentOS 等。

当使用 Image 启动一个 Container 后,一个新的可写的文件系统被加载到镜像的顶部,即:可写层,通常也称作 “容器层”,“容器层” 之下的都叫 “镜像层”。

nexus3 手动删除镜像 nexus镜像仓库_Dockerfile_02

Container 中运行的程序就是在这个 “容器层” 中执行的。第一次启动 Container 时,“容器层” 是空的,当文件系统发生变化,都会应用到这一层。如果想修改一个文件,该文件首先会从 “容器层” 下边的 “镜像只读层” 复制到可写层,该文件的只读版本依然存在,但是已经被可写层中的该文件副本所隐藏。这个是 Docker 重要的写时复制(copy on write)机制。

nexus3 手动删除镜像 nexus镜像仓库_Dockerfile_03

Docker Image 的生命周期如下图所示。

nexus3 手动删除镜像 nexus镜像仓库_Dockerfile_04

 五. Dockerfile详解


Dockerfile是一个包含用于组合映像的命令的文本文档。可以使用在命令行中调用任何命令。 Docker通过读取Dockerfile中的指令自动生成映像。

Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。

Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。有了 Dockerfile,当我们需要定制自己额外的需求时,只需在 Dockerfile 上添加或者修改指令,重新生成 image 即可,省去了敲命令的麻烦。

可以用一张图来说明:Docker镜像,Dockerfile ,容器之间的关系

nexus3 手动删除镜像 nexus镜像仓库_Dockerfile_05

1、Dockerfile的基本结构

Dockerfile 一般分为四部分:基础镜像信息、维护者信息、镜像操作指令、容器启动时执行指令.

##  Dockerfile文件格式

# This dockerfile uses the ubuntu image
# VERSION 2 - EDITION 1
# Author: docker_user
# Command format: Instruction [arguments / command] ..
 
# 1、第一行必须指定 基础镜像信息
FROM ubuntu
 
# 2、维护者信息
MAINTAINER docker_user docker_user@email.com
 
# 3、镜像操作指令
RUN apt-get update && apt-get install -y nginx

# 4、容器启动执行指令
CMD /usr/sbin/nginx

2、Dockerfile命令详细说明

Docker以从上到下的顺序运行Dockerfile的指令。为了指定基本映像,第一条指令必须是FROM。一个声明以字符开头则被视为注释。可以在Docker文件中使用RUNCMDFROMEXPOSEENV等指令。

在这里列出了一些常用的指令。

FROM:指定基础镜像

所有Dockerfile都必须以FROM命令开始。 FROM命令会指定镜像基于哪个基础镜像创建,接下来的命令也会基于这个基础镜像(译者注:CentOS和Ubuntu有些命令可是不一样的)。FROM命令可以多次使用,表示会创建多个镜像。

FROM <image>
FROM <image>:<tag>
FROM <image>:<digest> 
#三种写法,其中<tag>和<digest> 是可选项,如果没有选择,那么默认值为latest

MAINTAINER: 维护者信息

格式:
    MAINTAINER <author name>
示例:
    MAINTAINER Jasper Xu
    MAINTAINER sorex@163.com
    MAINTAINER Jasper Xu <sorex@163.com>

RUN:构建镜像时执行的命令

RUN用于在镜像容器中执行命令,其有以下两种命令执行方式:
shell执行
格式:
    RUN <command>
exec执行
格式:
    RUN ["executable", "param1", "param2"]
第二种是类似于函数调用。可将executable理解成为可执行文件,后面就是两个参数。
示例:
    RUN ["executable", "param1", "param2"]
    RUN apk update
    RUN ["/etc/execfile", "arg1", "arg1"]
注:
  RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache

ADD:将本地文件添加到容器中

tar类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似wget

复制文件指令。它有两个参数<source>和<destination>。destination是容器内的路径。source可以是URL或者是启动配置上下文中的一个文件。

格式:
    ADD <src>... <dest>
    ADD ["<src>",... "<dest>"] 用于支持包含空格的路径
示例:
    ADD hom* /mydir/          # 添加所有以"hom"开头的文件
    ADD hom?.txt /mydir/      # ? 替代一个单字符,例如:"home.txt"
    ADD test relativeDir/     # 添加 "test" 到 `WORKDIR`/relativeDir/
    ADD test /absoluteDir/    # 添加 "test" 到 /absoluteDir/

ADD 命令可以完成 COPY 命令的所有功能,并且还可以完成两类超酷的功能:

  1. 解压压缩文件并把它们添加到镜像中
  2. 从 url 拷贝文件到镜像中

当然,这些功能也让 ADD 命令用起来复杂一些,不如 COPY 命令那么直观。

1)解压压缩文件并把它们添加到镜像中
如果我们有一个压缩文件包,并且需要把这个压缩包中的文件添加到镜像中。需不需要先解开压缩包然后执行 COPY 命令呢?当然不需要!我们可以通过 ADD 命令一次搞定:

WORKDIR /app
ADD nickdir.tar.gz .
这应该是 ADD 命令的最佳使用场景了!

2)从 url 拷贝文件到镜像中
这是一个更加酷炫的用法!但是在 docker 官方文档的最佳实践中却强烈建议不要这么用!!docker 官方建议我们当需要从远程复制文件时,最好使用 curl 或 wget 命令来代替 ADD 命令。原因是,当使用 ADD 命令时,会创建更多的镜像层,当然镜像的 size 也会更大(下面的两段代码来自 docker 官方文档):

ADD http://example.com/big.tar.xz /usr/src/things/
RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
RUN make -C /usr/src/things all
如果使用下面的命令,不仅镜像的层数减少,而且镜像中也不包含 big.tar.xz 文件:

RUN mkdir -p /usr/src/things \
    && curl -SL http://example.com/big.tar.xz \
    | tar -xJC /usr/src/things \
    && make -C /usr/src/things all
好吧,看起来只有在解压压缩文件并把它们添加到镜像中时才需要 ADD 命令!
 

COPY:功能类似ADD

但是是不会自动解压文件,也不能访问网络资源:

除了指定完整的文件名外,COPY 命令还支持 Go 风格的通配符,比如:

COPY check* /testdir/           # 拷贝所有 check 开头的文件
COPY check?.log /testdir/       # ? 是单个字符的占位符,比如匹配文件 check1.log
对于目录而言,COPY 和 ADD 命令具有相同的特点:只复制目录中的内容而不包含目录自身。

比如我们在 Dockerfile 中添加下面的命令:

在制作 docker 镜像时,有复制某一个路径下所有文件和文件夹到镜像的需求,写下了如下 dockerfile:

FROM alpine
WORKDIR /root/test_docker_proj
COPY * ./

原始目录结构是这样的:

/projects/test_docker_proj
├── Dockerfile
├── dir1
│   ├── dir11
│   │   └── file11
│   └── file1
└── file2

然而复制到 docker 镜像里的目录结构变成了这样:

/root/test_docker_proj
├── Dockerfile
├── dir11
│   └── file11
├── file1
└── file2

可以看到 dir1 这个文件夹并没有被复制到镜像里,但是 dir1 中的子文件夹和文件都被复制进来了,和 dir1 同级的文件也被复制了。也就是说,在 COPY 执行的过程中,第一层文件夹被「解包」了。

 

CMD:构建容器后调用,也就是在容器启动时才进行调用。

格式:
    CMD ["executable","param1","param2"] (执行可执行文件,优先)
    CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数)
    CMD command param1 param2 (执行shell内部命令)
示例:
    CMD echo "This is a test." | wc -
    CMD ["/usr/bin/wc","--help"]
注:
   CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。

ENTRYPOINT:配置容器,使其可执行化。

配合CMD可省去"application",只使用参数。

docker run
docker run

LABEL:用于为镜像添加元数据

格式:
    LABEL <key>=<value> <key>=<value> <key>=<value> ...
示例:
  LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"
注:
  使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。

ENV:设置环境变量

格式:
    ENV <key> <value>  #<key>之后的所有内容均会被视为其<value>的组成部分,因此,一次只能设置一个变量
    ENV <key>=<value> ...  #可以设置多个变量,每个变量为一个"<key>=<value>"的键值对,如果<key>中包含空格,可以使用\来进行转义,也可以通过""来进行标示;另外,反斜线也可以用于续行
示例:
    ENV myName John Doe
    ENV myDog Rex The Dog
    ENV myCat=fluffy

EXPOSE:指定于外界交互的端口

docker run
-P

VOLUME:用于指定持久化目录

格式:

VOLUME ["/path/to/dir"]
示例:
    VOLUME ["/data"]
    VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"
注:
  一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
1 卷可以容器间共享和重用
2 容器并不一定要和其它容器共享卷
3 修改卷后会立即生效
4 对卷的修改不会对镜像产生影响
5 卷会一直存在,直到没有任何容器在使用它

WORKDIR:工作目录,类似于cd命令

docker run

USER:指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。

使用USER指定用户时,可以使用用户名、UID或GID,或是两者的组合。当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户

 格式:
  USER user
  USER user:group
  USER uid
  USER uid:gid
  USER user:gid
  USER uid:group

 示例:
  USER www

 注:

  使用USER指定用户后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT都将使用该用户。镜像构建完成后,通过docker run运行容器时,可以通过-u参数来覆盖所指定的用户。

ARG:用于指定传递给构建运行时的变量

构建参数,作用于ENV相同,不同的是ARG的参数只在构建镜像的时候起作用,也就是docker build的时候。

Dockerfile中的ARG指令用以定义构建时需要的参数,使用格式如下:

格式:
    ARG <name>[=<default value>]
示例:
    ARG site
    ARG build_user=www

ARG指令定义的参数,在docker build命令中以--build-arg a_name=a_value形式赋值。

如果docker build命令传递的参数,在Dockerfile中没有对应的参数,将抛出如下警告:

[Warning] One or more build-args [foo] were not consumed.

如果在Dockerfile中,ARG指令定义参数之前,就有其他指令引用了参数,则参数值为空字符串。

ARG指令定义参数在CMD指令为空。

不建议在构建的过程中,以参数的形式传递保密信息,如key, password等。

Docker自带的如下ARG参数,可以在其他指令中直接引用:

  • HTTP_PROXY
  • http_proxy
  • HTTPS_PROXY
  • https_proxy
  • FTP_PROXY
  • ftp_proxy
  • NO_PROXY
  • no_proxy

ONBUILD:用于设置镜像触发器

格式:
  ONBUILD [INSTRUCTION]
示例:
  ONBUILD ADD . /app/src
  ONBUILD RUN /usr/local/bin/python-build --dir /app/src
注:
  当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被钥触发

以下是一个小例子:

# This my first nginx Dockerfile
# Version 1.0

# Base images 基础镜像
FROM centos

#MAINTAINER 维护者信息
MAINTAINER tianfeiyu 

#ENV 设置环境变量
ENV PATH /usr/local/nginx/sbin:$PATH

#ADD  文件放在当前目录下,拷过去会自动解压
ADD nginx-1.8.0.tar.gz /usr/local/  
ADD epel-release-latest-7.noarch.rpm /usr/local/  

#RUN 执行以下命令 
RUN rpm -ivh /usr/local/epel-release-latest-7.noarch.rpm
RUN yum install -y wget lftp gcc gcc-c++ make openssl-devel pcre-devel pcre && yum clean all
RUN useradd -s /sbin/nologin -M www

#WORKDIR 相当于cd
WORKDIR /usr/local/nginx-1.8.0 

RUN ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_ssl_module --with-pcre && make && make install

RUN echo "daemon off;" >> /etc/nginx.conf

#EXPOSE 映射端口
EXPOSE 80

#CMD 运行以下命令
CMD ["nginx"]

三、 docker 仓库



1、docker 官方仓库

1.1 下载官方的 CentOS 镜像到本地

   docker pull centos

    默认会从docker.io上下载镜像。

1.2  搜索官方的 CentOS 镜像

[root@iZ235fz06auZ docker]# docker search centos
INDEX       NAME                                     DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
docker.io   docker.io/centos                         The official build of CentOS.                   3476      [OK]       
docker.io   docker.io/jdeathe/centos-ssh             CentOS-6 6.9 x86_64 / CentOS-7 7.3.1611 x8...   77                   [OK]
docker.io   docker.io/tutum/centos                   Simple CentOS docker image with SSH access      32                   
docker.io   docker.io/kinogmt/centos-ssh             CentOS with SSH                                 15                   [OK]

STARS:星级( 表示该镜像的受欢迎程度)

OFFICIAL:是否官方创建

AUTOMATED:是否自动创建。 

官方的镜像说明是官方项目组创建和维护的,automated资源允许用户验证镜像的来源和内容。

根据是否是官方提供, 可将镜像资源分为两类。 一种是类似centos这样的基础镜像, 被称为基础或根镜像。这些基础镜像是由Docker公司创建、验证、 支持、 提供。这样的镜像往往使用单个单词作为名字。
 

还有一种类型, 比如 tianon/centos 镜像, 它是由 Docker 的用户创建并维护的, 往往带有用户名称前缀。 可以通过前缀user_name/来指定使用某个用户提供的镜像, 比如tianon 用户。

另外, 在查找的时候通过-s N 参数可以指定仅显示评价为N星以上的镜像。

1.3修改默认的仓库地址

修改成阿里云:
vi  /etc/docker/daemon.json
{
  "registry-mirrors": ["https://3bxiiqzd.mirror.aliyuncs.com"]
}

2. docker 私有仓库

有时候使用 Docker Hub 这样的公共仓库可能不方便, 用户可以创建一个本地仓库供私人使用。

   Registry在github上有两份代码:老代码库和新代码库。老代码是采用python编写的,存在pull和push的性能问题,出到0.9.1版本之后就标志为deprecated,不再继续开发。从2.0版本开始就到在新代码库进行开发,新代码库是采用go语言编写,修改了镜像id的生成算法、registry上镜像的保存结构,大大优化了pull和push镜像的效率。

2.1  私有仓库镜像安装

    官方在Docker hub上提供了registry的镜像(详情),我们可以直接使用该registry镜像来构建一个容器,搭建我们自己的私有仓库服务。Tag为latest的registry镜像是0.9.1版本的,我们直接采用2.1.1版本。

1、docker run -d -p 5000:5000 registry
1)指定私有仓库位置:

用户可以通过指定参数来配置私有仓库位置, 例如配置镜像存储到Amazon S3 服务。
$ sudo docker run \
   -e SETTINGS_FLAVOR=s3 \
   -e AWS_BUCKET=acme-docker \
   -e STORAGE_PATH=/registry \
   -e AWS_KEY=AKIAHSHB43HS3J92MXZ \
   -e AWS_SECRET=xdDowwlK7TJajV1Y7EoOZrmuPEJlHYcNP2k4j49T \
   -e SEARCH_BACKEND=sqlalchemy \
   -p 5000:5000 \
  registry
2)配置文件:
还可以指定本地路径( 如/home/user/registry-conf) 下的配置文件
docker run -d -p 5000:5000 -v /etc/docker/registry/config.yml:/etc/docker/registry/config.yml registry

3)仓库本地:

之前老版Register,默认上传的镜像保存在容器的位置是/tmp/registry 。新registry的仓库目录是在/var/lib/registry,所以运行时挂载目录需要注意。

docker run -d -p 5000:5000 -v /data/registry:/var/lib/registry registry
     我们将主机的/data/registry目录挂载到该目录,即可实现将镜像保存到主机的/data/registry目录了。

2.2、登陆私有仓库:

 docker login --username $DOCKER_USER   registry.xxxx.com

要以非交互方式运行该命令,您可以设置 flag 以提供密码通过。使用防止密码最终出现在外壳的历史记录中, 或日志文件。

下面的示例从文件中读取密码,并使用以下命令将其传递给命令:

docker login https://xxx.com --username macy.hou --password-stdin < /root/.docker/passwd

cat /root/.docker/passwd |docker login https://xxx.com -u macy.hou --password-stdin


也可以以环境变量形式登录,以下示例从变量读取密码,然后使用STDIN将其传递给docker login命令:

echo "$PASSWORD" | docker login --username foo --password-stdin

linux下可以通过/etc/profile 设置 PASSWORD变量

2.4  上传pull

创建好私有仓库之后, 就可以使用 docker tag 来标记一个镜像, 然后推送它到本地仓库,别的机器上就可以下载下来了。 例如私有仓库本地地址为127.0.0.1:5000。

$ docker tag java8  127.0.0.1:5000/java8


使用 docker push 上传标记的镜像使用 docker push 上传标记的镜像


$ docker push 127.0.0.1:5000/java8

当使用curl http://192.168.0.100:5000/v2/_catalog能看到json格式的返回值时,说明registry已经运行起来了。   

2.4  远程访问


   到目前为止,docker registry 已经可以正常使用,且可以指定数据存储位置。但也只能在本地使用,要想在远程使用该 registry,就必须使用 TLS 来确保通信安全,就像使用 SSL 来配置 web 服务器。也可以强制 docker registry 运行在 insecure 模式,这种模式虽然配置起来要简单一些,但很不安全,一般不建议使用。


这里偷懒使用这个简单的 insecure 模式,假设你在一个域名为 test.docker.midea.registry.hub 的主机上运行 docker registry,步骤如下:


/etc/default/docker 或  /etc/sysconfig/docker,具体是哪个取决于你的系统。


DOCKER_OPTS



ADD_REGISTRY='--add-registry test.docker.midea.registry.hub:5000'  
DOCKER_OPTS="--insecure-registry test.docker.midea.registry.hub:5000"  
INSECURE_REGISTRY='--insecure-registry test.docker.midea.registry.hub:5000'

3、重启你的 docker 守护进程

通过以上3步,你的这个机器就能远程从 test.docker.midea.registry.hub 上运行的 docker registry 拉取镜像了

2.5 本地安装运行

有时候需要本地运行仓库服务,可以通过源码方式进行安装。首先安装Golang环境支持,以Ubuntu为例,可以执行如下命令:
$ sudo add-apt-repository ppa:ubuntu-lxc/lxd-stable
$ sudo apt-get update
$ sudo apt-get install golang
确认Golang环境安装成功,并配置$GOPATH环境变量,例如/go。
创建$GOPATH/src/github.com/docker/目录,并获取源码,如下所示:


$ mkdir -p $GOPATH/src/github.com/docker/
$ cd $GOPATH/src/github.com/docker/
$ git clone https://github.com/docker/distribution.git
$ cd distribution
将自带的模板配置文件复制到/etc/docker/registry/路径下,创建存储目录/var/lib/registry:


$ cp cmd/registry/config-dev.yml /etc/docker/registry/config.yml
$ mkdir -p /var/lib/registry
然后执行安装操作:
$ make PREFIX=/go clean binaries
编译成功后,可以通过下面的命令来启动:
$ registry server /etc/docker/registry/config.yml
此时使用访问本地的5000端口,看到返回成功(200 OK),则说明运行成功:
$ curl -i 127.0.0.1:5000/v2/
HTTP/1.1 200 OK

3. Registry 仓库v2认证模式

Docker Registry v2的认证模式和v1有了较大的变化,降低了系统的复杂度、减少了服务之间的交互次数,其基本工作模式:

nexus3 手动删除镜像 nexus镜像仓库_容器_06

具体交互过程包括如下步骤:
1)Docker Daemon或者其他客户端尝试访问Registry服务器,比如pull、push或者访问manifiest文件;
2)在Registry服务器开启了认证服务模式时,就会直接返回401 Unauthorized错误,并通知调用方如何获得授权;
3)调用方按照要求,向Authorization Service发送请求,并携带Authorization Service需要的信息,比如用户名、密码;
4)如果授权成功,则可以拿到合法的Bearer token,来标识该请求方可以获得的权限;
5)请求方将拿到Bearer token加到请求的Authorization header中,再次尝试步骤1中的请求;
6)Registry服务通过验证Bearer token以及JWT格式的授权数据,来决定用户是否有权限进行请求的操作。
当启用认证服务时,需要注意以下两个地方:


  • 对于Authentication Service,Docker官方目前并没有放出对应的实现方案,需要自行实现对应的服务接口;
  • Registry服务和Authentication服务之间通过证书进行Bearer token的生成和认证,所以要保证两个服务之间证书的匹配。

除了使用第三方实现的认证服务(如docker_auth、SUSE Portus等)外,还可以通过Nginx代理方式来配置基于用户名密码的认证。

4. Nexus3作为私有镜像仓库

使用nexus3作为私有仓库是最简单的方式。

4.1 、安装

1.下载Nexus:
  下载最新版的nexus下载地址: https://www.sonatype.com/oss-thank-you-tar.gz
2.创建nexus文件夹并解压:
  mkdir /mnt/app/nexus
  tar -xvf   nexus-3.15.2-01-unix.tar.gz -C  /mnt/app/nexus
3.使用java8启动:
  修改bin/nexus :
  INSTALL4J_JAVA_HOME_OVERRIDE=/usr/java8/
  进入nexus-3.15.2-01/bin目录下,执行./nexus start 命令启动
  启动成功后要等一会儿,8081端口才会起来 ,可以使用lsof -i:8081 命令查看端口占用情况。

4.安全起见,我们建立一个nexus用户用来启动nexus
   adduser nexus
   更改nexus文件夹的访问权限更改为nexus用户
   sudo chown -R nexus:nexus  /nexus
   打开/nexus/bin/nexus.rc 文件, 修改启动用户如下
   run_as_user=”nexus”

5.如果你想更改默认的数据目录,可以打开nexus的配置文件,修改-Dkaraf.data属性。
   vi /nexus/nexus/bin/nexus.vmoptions
下面来一个例子

-Xms1200M
-Xmx1200M
-XX:+UnlockDiagnosticVMOptions
-XX:+UnsyncloadClass
-Djava.net.preferIPv4Stack=truer
-Dkaraf.home=.
-Dkaraf.base=.
-Dkaraf.etc=etc
-Djava.util.logging.config.file=etc/java.util.logging.properties
-Dkaraf.data=/nexus/nexus-data
-Djava.io.tmpdir=data/tmp
-Dkaraf.startLocalConsole=false

6. 修改端口号: etc/nexus-default.properties

 

nexus3 手动删除镜像 nexus镜像仓库_容器_07

 7:  supervisor启动:

 [program:turing-nexus2]
command=/mnt/app/nexus/bin/nexus run
process_name=%(program_name)s
numprocs=1
directory=/mnt/app/nexus
umask=022
user=appuser
stdout_logfile=/mnt/logs/turing-nexus2/server.log
stderr_logfile=/mnt/logs/turing-nexus2/error.log
environment=
serverurl=AUTO

4.2 、配置使用

访问地址:http://192.168.10.50:18082/

使用域名:http://nexus.xxxxx.com  admin admin123

首次默认登陆账号:admin admin123

nexus可以作用yum的私库,maven私库、nuget等,可以参见官方说明,我们这里只是针对docker的私有镜像进行配置

代理镜像库(proxy repository)的配置和访问:在内网总是有下载hub.docker.com 的需求,可以通过配置nexus的代理模式来实现

nexus3 手动删除镜像 nexus镜像仓库_运维_08

4.3、配置公共读:

nexus3 手动删除镜像 nexus镜像仓库_nexus3 手动删除镜像_09

4.4、nginx代理

配置host repository的HTTPS访问:nginx代理

nexus3 手动删除镜像 nexus镜像仓库_docker_10

设置Docker Bearer Token Realm可用:

nexus3 手动删除镜像 nexus镜像仓库_Dockerfile_11

 5、docker使用私有registry仓库

1、登陆:

     docker login xxxx.com#登陆
      需要输入创建repository时指定的账号和密码 登陆成功后可以pull私有库的镜像。

 2、拉取镜像:

       docker pull xxxx.com/nginx # 拉取xxxx.com上的nginx镜像,如果没有则拉取失败
 3、提交本地镜像nexus仓库:

       创建好私有仓库之后, 就可以使用 docker tag 来标记一个镜像, 然后推送它到本地仓库,别的机器上就可以下载下来了。 例如 标记镜像:

     docker tag java8  xxxx.com/java8

nexus3 手动删除镜像 nexus镜像仓库_运维_12

         使用 docker push 上传标记的镜像使用 docker push 上传标记的镜像
4、上传镜像:

       docker push xxxx.com/java8

5、测试:

    1)使用curl http://xxxx.com/v2/_catalog能看到json格式的返回值时,说明registry已经运行起来了。

     2)# docker search  registry.xxxx.com/java8        
     INDEX     NAME      DESCRIPTION   STARS     OFFICIAL   AUTOMATED

6、保存私有仓库的登陆信息文件位置:

     我们在命令行方式下,输入docker login登陆成功后,会在 ~/.docker/目录下生成一个config.json文件。打开后可以看到如下的内容:

# cat ~/.docker/config.json
{
         "auths": {
                 "registry.xxxx.com": {
                         "auth": "cmVnaXN0cnktYWRtaW46cmVnaXN0cnktYWRtaW4="
                 }
         }}

    如果不logout ,下次拉取镜像就不再需要输入账号和密码:

    这种方式,在kubernetes 中使用deployment定义一个pod,是不能下载镜像成功的。

四、k8s使用私有仓库


(后续章节我们讲到)

通常情况下,在私有云环境中使用kubernetes时,我们要从docker registry拉取镜像的时候,都会给docker daemo配置--insecure-registry属性来告诉docker daemo我们所使用的docker registry是可信的,这样才能从私有的docker registry中拉取镜像,但是如果要使用nexus作为kubernetes的镜像仓库的话,这种方式就不适用了,下面让我们看看如何来使用nexus作为kubernetes的镜像仓库。

1、kubenetes设置pause镜像

由于在Kubenetes中是以pod而不是Docker容器管理单元,在kubelet创建pod的时候,还通过启动一个名为google_containers/pause的镜像来实现pod概念。

Pause容器 全称infrastucture container(又叫infra)基础容器。其使用c语言编写,官方使用的镜像为gcr.io/google_containers/pause-amd64:3.1

nexus3 手动删除镜像 nexus镜像仓库_nexus3 手动删除镜像_13

kubernetes中的pause容器主要为每个业务容器提供以下功能:

PID命名空间:Pod中的不同应用程序可以看到其他应用程序的进程ID。

网络命名空间:Pod中的多个容器能够访问同一个IP和端口范围。

IPC命名空间:Pod中的多个容器能够使用SystemV IPC或POSIX消息队列进行通信。

UTS命名空间:Pod中的多个容器共享一个主机名;Volumes(共享存储卷):

Pod中的各个容器可以访问在Pod级别定义的Volumes。

我们可以给每台node的kubelet服务启动参数加上--pod_infra_container_image参数,指定pause镜像地址。例如指定为官方基础镜像:

 kubelet --kubeconfig=/mnt/app/kubernetes/conf/kubelet.yaml --hostname-override=192.68.10.37 --logtostderr=false --log-dir=/mnt/logs/k8s-kubelet/ --v=2 --cgroup-driver=systemd --runtime-cgroups=/systemd/system.slice --kubelet-cgroups=/systemd/system.slice  --pod_infra_container_image=docker.io/mirrorgooglecontainers/pause-amd64:3.1

由于我们使用私有仓库,需要将其下载,导出或者标记,再push到私有Docker registry中去。

docker pull mirrorgooglecontainers/pause-amd64:3.1

docker tag  da86e6ba6ca1 registry.xxxx.com/pause-amd64

docker push  registry.xxxx.com/pause-amd64

nexus3 手动删除镜像 nexus镜像仓库_容器_14

之后修改--pod_infra_container_image参数指定为私有仓库镜像:

--pod_infra_container_image=registry.xxx.com/pause-amd64

然后重启kubelet服务

2、设置k8s的Secret

k8s的Secret类型

Kubernetes提供了Secret来处理敏感信息,目前Secret的类型有3种:

  • Opaque:使用base64编码存储信息,可以通过base64 --decode解码获得原始数据,因此安全性弱。
  • kubernetes.io/dockerconfigjson:用于存储docker registry的认证信息,作用于Docker registry(nexus),用户下载docker镜像认证使用。
  • kubernetes.io/service-account-token:用于被 serviceaccount 引用。serviceaccout 创建时 Kubernetes 会默认创建对应的 secret。Pod 如果使用了 serviceaccount,对应的 secret 会自动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中。

3、k8s的registry认证Secret

当pod从私用仓库拉取镜像时,k8s集群使用类型为docker-registry的Secret来提供身份认证,创建一个名为registry-key的Secret,执行如下命令:

$ kubectl delete secret registry-key
$ kubectl -n k8s-dev create secret docker-registry registry-key-secret \
--docker-server=registry.xxxx.com.com \
--docker-username=registry-admin \
--docker-password=registry-admin \
--docker-email=xxxxx@qq.com

        

nexus3 手动删除镜像 nexus镜像仓库_docker_15



注意 -n k8s-dev为指定命名空间,一般搭建k8s集群时,建议新建一个命名空间来隔离资源。

检查Secret: kubectl get secret registry-key-secret  -o yaml

nexus3 手动删除镜像 nexus镜像仓库_docker_16

通过 base64 对 secret 中的内容解码:

nexus3 手动删除镜像 nexus镜像仓库_运维_17

也可以直接读取 ~/.dockercfg 的内容来创建:

$ kubectl create secret docker-registry registry-key-secret   --from-file="~/.dockercfg"

4、配置和部署Pod

imagePullSecrets标签指定拉取镜像时的身份验证信息

在创建 Pod 的时候,通过 imagePullSecrets 来引用registry-key-secret:指定拉取镜像时的身份验证信息

nexus3 手动删除镜像 nexus镜像仓库_容器_18

springboot-deployment.yml: 

apiVersion: v1
 kind: Pod
 metadata:
   name: springbootweb1
 spec:
   containers:
     - name: springbootweb1
       image: registry.xxxx.com/springboot:latest
   imagePullSecrets:
     - name: registry-key-secret

nexus3 手动删除镜像 nexus镜像仓库_容器_19

五、问题


问题1:登陆出现401 Unauthorized

Error response from daemon: login attempt to https://registry.xxxx.com/v2/ failed with status: 401 Unauthorized

解决:Docker Bearer Token Realm可用:

nexus3 手动删除镜像 nexus镜像仓库_Dockerfile_11