Docker第二篇:镜像的基本使用-搭建Centos系统

镜像操作篇

大多数的运行都依赖于操作系统,当然有些可以单独运行比如hello word,
以centos的镜像为例 ,

注意前提是要修改镜像加速器【参考 配置镜像加速器】,否则下面对于翻墙安装来说非常浪费时间,或者根本安装不成功。

配置镜像加速器
https://blog.csdn.net/zjcjava/article/details/91380509

镜像操作涉及到的内容

docker image、容器以及命令操作

docker image是一个极度精简版的Linux程序运行环境,官网的java镜像包括的东西更少,除非是镜像叠加方式的如centos+java7
docker image是需要定制化build的一个安装包,包括基础镜像+应用的二进制部署包
docker image内不建议有运行期需要修改的配置文件

Dockerfile用来创建一个自定义的image,包含了用户指定的软件依赖,环境配置等以命令配置的方式统一在一个文件中,可以方便的使用这个文件创建镜像。当前目录下包含Dockerfile,使用命令build来创建新的docker image,整个操作流程更加简洁方便

docker image的最佳实践之一是尽量重用和使用网上公开的基础镜像,在其基础上安装自己需要的服务和软件构建成自己的所需的镜像文件

Docker container:容器

Docker container是image的实例,共享内核,即它是docker image的运行后的实体
Docker container里可以运行不同os的image,比如Ubuntu的或者centos
Docker container不建议内部开启一个sshd服务,1.3版本后新增了docker exec命令进入容器进行排查问题
Docker container没有ip地址,通常不会有服务端口暴露,是一个封闭的沙盒

Docker daemon:
Docker daemon是创建和运行container的Linux守护进程,也是Docker 最主要的核心组件
Docker daemon可以理解为Docker container的container
Docker daemon可以绑定本地端口并提供REST API服务,用来远程访问和控制

镜像操作

查找仓库中可以用的镜像

docker search centos

在docker中安装CENTOS

docker pull centos

默认会安装官方提供的最新版本镜像

查看已经安装的镜像列表

docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos              latest              e934aafc2206        2 weeks ago         199MB
lwieske/java-8      latest              6e05355899ef        3 months ago        164MB
hello-world         latest              f2a91732366c        5 months ago        1.85kB

REPOSITORY:镜像名称
TAG:标签
IMAGE ID:镜像短ID
CREATED:镜像创建时间
SIZE:镜像大小

用 ID、镜像名、摘要删除镜像

从上面的镜像列表中可以知道,镜像列表的信息
可以根据这些信息删除该镜像

docker image rm lwieske/java-8
Untagged 和 Deleted

如果观察上面这几个命令的运行输出信息的话,你会注意到删除行为分为两类,一类是 Untagged,另一类是 Deleted。我们之前介绍过,镜像的唯一标识是其 ID 和摘要,而一个镜像可以有多个标签。

因此当我们使用上面命令删除镜像的时候,实际上是在要求删除某个标签的镜像。所以首先需要做的是将满足我们要求的所有镜像标签都取消,这就是我们看到的 Untagged 的信息。因为一个镜像可以对应多个标签,因此当我们删除了所指定的标签后,可能还有别的标签指向了这个镜像,如果是这种情况,那么 Delete 行为就不会发生。所以并非所有的 docker rmi 都会产生删除镜像的行为,有可能仅仅是取消了某个标签而已。

当该镜像所有的标签都被取消了,该镜像很可能会失去了存在的意义,因此会触发删除行为。镜像是多层存储结构,因此在删除的时候也是从上层向基础层方向依次进行判断删除。镜像的多层结构让镜像复用变动非常容易,因此很有可能某个其它镜像正依赖于当前镜像的某一层。这种情况,依旧不会触发删除该层的行为。直到没有任何层依赖当前层时,才会真实的删除当前层。这就是为什么,有时候会奇怪,为什么明明没有别的标签指向这个镜像,但是它还是存在的原因,也是为什么有时候会发现所删除的层数和自己 docker pull 看到的层数不一样的源。

除了镜像依赖以外,还需要注意的是容器对镜像的依赖。如果有用这个镜像启动的容器存在(即使容器没有运行),那么同样不可以删除这个镜像。之前讲过,容器是以镜像为基础,再加一层容器存储层,组成这样的多层存储结构去运行的。因此该镜像如果被这个容器所依赖的,那么删除必然会导致故障。如果这些容器是不需要的,应该先将它们删除,然后再来删除镜像。

用 docker image ls 命令来配合
像其它可以承接多个实体的命令一样,可以使用 docker image ls -q 来配合使用 docker image rm,这样可以成批的删除希望删除的镜像。我们在“镜像列表”章节介绍过很多过滤镜像列表的方式都可以拿过来使用。

比如,我们需要删除所有仓库名为 redis 的镜像:

$ docker image rm $(docker image ls -q redis)
或者删除所有在 mongo:3.2 之前的镜像:

$ docker image rm $(docker image ls -q -f before=mongo:3.2)

容器操作

使用镜像运行容器

docker run <相关参数> <镜像 ID> <初始命令>

docker run -it --rm centos bash

docker run 就是运行容器的命令,具体格式我们会在 容器 一节进行详细讲解,我们这里简要的说明一下上面用到的参数。
• -it :这是两个参数,一个是 -i :交互式操作直接进入到container容器中,一个是 -t 终端tty,伪终端。我们这里打算进入 bash 执行一些命令并查看返回结果,因此我们需要交互式终端。
• --rm :这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动 docker rm 。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用 --rm 可以避免浪费空间。
• centos :这是指用 centos 镜像为基础来启动容器。
• -h :指定为container设置hostname的名称,省略时为随机值eg:-h bamboo 指定容器的名称为bmaoo
• -v:表示需要将本地哪个目录挂载到容器中 (这个目录和本地是交互的,目录下的文件在容器和本地上是可以相互看见的)
格式:-v <宿主机目录>:<容器目录>
• bash :放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 bash 。

会自动进入容器,运行如下命令

[root@ac43d254403c /]# uname -a

查看系统版本号,可以看到内核和64位的版本

[root@ac43d254403c /]# cat /etc/os-release

可以看到更详细的系统版本情况

ac43d254403c 这个很重要,用来标记容器实例的名称

通过 exit 退出这个容器,这个容器也随之删除了

后台模式启动容器(正式环境使用)

在正式使用时我们当然不能会每次都在退出终端时删除容器了,那样就没法回到宿主机下了。因此我们常使用的方式是让容器实例进入后台模式运行,并执行打印输出hello world到docker中的实例控制台

docker run -d centos bash -c "while true; do echo hello world; sleep 1; done"
6a85f6eae05c50efacf3e592ad2208d8a5ec2ab1c7191cce6ac1c1d9c5f7875b

在输出中,我们没有看到是一串长字符
6a85f6eae05c50efacf3e592ad2208d8a5ec2ab1c7191cce6ac1c1d9c5f7875b
这个长字符串叫做容器ID,对每个容器来说都是唯一的
因为一个机器可以启动多个容器,这个ID就起到了唯一标识的作用

查看运行的容器实例进程

 docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
5f0580926e17        centos              "/bin/sh -c 'while t…"   5 seconds ago       Up 4 seconds                            vigilant_tesla

CONTAINER ID:容器ID
NAMES:自动分配的容器名称
COMMAND :执行的命令

  • 在容器内使用docker logs命令,查看容器内的标准输出
    docker logs 容器ID或者NAMES
docker logs 5f05
hello world
hello world

停止容器

我们使用 docker stop 命令来停止容器:

docker stop vigilant_tesla

或者是使用ID
docker stop 5f05

启动容器

docker start vigilant_tesla

上面我们关闭的容器实例运行起来了, docker ps可以看到它的启动状态

退出容器交互

退出容器:
exit
或者
Ctrl+P+Q
快捷键方式,如果交互模式是每一秒打印一句hello word,那么无法使用命令行退出,只能选择快捷键方式退出

在容器中执行命令

交互模式下我们可以直接运行命令,但是当后台模式时如何执行命令呢
docker exec表示在一个运行的container中执行命令

docker run -d -v /data -h bamboo centos
docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
292cf95a7853        centos      "bash -c 'while tr..."         8 minutes ago         Up 8 minutes        80
执行某一个命令ls /
[root@docker ~]# docker exec -it 292cf95a7853 ls /
anaconda-post.log  bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
还可以标准输入命令:
[root@docker ~]# docker exec  292cf95a7853 echo hello
hello

进入Docker容器

当后台模式时如何进入交互模式

进入Docker容器比较常见的几种做法如下:

使用docker attach:Docker提供了attach命令来进入Docker容器,不推荐
使用SSH:不推荐
使用nsenter:需要安装
使用exec :docker 1.3之后的版本自带的工具,推荐

然后我们使用docker ps查看到该容器信息,接下来就使用docker

attach进入该容器
使用docker attach

$ sudo docker attach 44fc0f0582d9  

但在,使用该命令有一个问题。当多个窗口同时使用该命令进入该容器时,所有的窗口都会同步显示。如果有一个窗口阻塞了,那么其他窗口也无法再进行操作。

使用SSH进入Docker容器
  在生产环境中排除了使用docker attach命令进入容器之后,相信大家第一个想到的就是ssh。在镜像(或容器)中安装SSH Server,这样就能保证多人进入

容器且相互之间不受干扰了,相信大家在当前的生产环境中(没有使用Docker的情况)也是这样做的。但是使用了Docker容器之后不建议使用ssh进入到Docker容

器内。关于为什么不建议使用,请参考如下文章:

为什么不需要在 Docker 容器中运行 sshd?
https://www.oschina.net/translate/why-you-dont-need-to-run-sshd-in-docker?cmp

使用nsenter进入Docker容器
  在上面两种方式都不适合的情况下,还有一种比较方便的方法,即使用nsenter进入Docker容器。关于什么是nsenter请参考如下文章:

https://github.com/jpetazzo/nsenter

在了解了什么是nsenter之后,系统默认将我们需要的nsenter安装到主机中

如果没有安装的话,按下面步骤安装即可(注意是主机而非容器或镜像)

具体的安装命令如下:

$ wget https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz  
$ tar -xzvf util-linux-2.24.tar.gz  
$ cd util-linux-2.24/  
$ ./configure --without-ncurses  
$ make nsenter  
$ sudo cp nsenter /usr/local/bin  

安装好nsenter之后可以查看一下该命令的使用。
 nsenter可以访问另一个进程的名称空间。所以为了连接到某个容器我们还需要获取该容器的第一个进程的PID。可以使用docker inspect命令来拿到该PID。

docker inspect命令使用如下:

拿到容器ID
docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
292cf95a7853        centos      "bash -c 'while tr..."         8 minutes ago         Up 8 minutes        80

用docker inspect来查看该容器的详细信息。
$ sudo docker inspect 292cf95a7853

由其该信息非常多,此处只截取了其中一部分进行展示。如果要显示该容器第一个进行的PID可以使用如下方式

[root@localhost ~]# sudo docker inspect -f {{.State.Pid}} 292cf95a7853
12151
# 在拿到该进程PID之后我们就可以使用nsenter命令访问该容器了,其中的12151即刚才拿到的进程的PID
[root@localhost ~]#  sudo nsenter --target 12151 --mount --uts --ipc --net --pid  
# 可以看到机器的hostname已经变成我们刚刚设置成的bamboo的机器了
[root@bamboo /]# ls
anaconda-post.log  boot  dev  home  lib64  mnt  proc  run   srv  tmp  var
bin                data  etc  lib   media  opt  root  sbin  sys  usr
[root@bamboo /]# 

使用docker exec进入Docker容器

除了上面几种做法之外,docker在1.3.X版本之后还提供了一个新的命令exec用于进入容器,这种方式相对更简单一些,下面我们来看一下该命令的使用:

$ sudo docker exec --help  

接下来我们使用该命令进入一个已经在运行的容器,可以看到可以成功进入容器

$ sudo docker ps  
$ sudo docker exec -it  292cf95a7853 /bin/bash  
[root@bamboo /]# ls
anaconda-post.log  boot  dev  home  lib64  mnt  proc  run   srv  tmp  var

删除容器

每次重新启动容器时容器名称取的和上一次会一模一样是,如果没有删除已经运行过的容器那么会报异常

You have to remove (or rename) that container to be able to reuse that name

docker rm 5e9b198b3dcb      # 删除运行的容器

这样再启动容器同名时就不会再报异常错误了

docker容器的网络,文件配置信息

[root@docker ~]# nsenter --target `docker inspect -f {{.State.Pid}} 292cf95a7853` --net --ipc --pid --mount --uts
[root@292cf95a7853 /]# ls

运行一个container的本身就是开启一个具有独立namespace的进程
进程有自己的网络,文件系统等
nsenter是关于namespace命名空间的命令,能够是一些资源能够进行隔离

PID:进程隔离(process id)
  NET:网络接口(network)
  IPC:管理跨进程通信的访问(interprocess communication)
  MNT:管理挂载点(mount)
  UTS:隔离内核和版本标识(unix timesharing system)
  USER:隔离用户

可以通过docker ps来查看container的uuid和运行信息
可以通过指定–name的方式来指定container的名字,name必须唯一

inspect:可以查看container的更多信息
  通过docker inspect {container_id}来获取container的更多的信息,包括网络,volume,实际在host上的进程id等信息

log
  通过logs命令可以看到container中command所指向进程的STDOUT,STDERR数据
  可以进程排错(-d后台运行没有输出到console时,查看)

环境变量
  通过-e参数,可以在运行container的时候添加系统环境变量

网络设置
  docker使用bridge桥接的方式来实现container之间以及和外部的通信
network架构:
  在host主机上的一个veth{id}的虚拟网卡和一个container里面的eth0网卡一一映射
  host上的bridge负责把数据流在不同的veth间转发,实现网络的IO
  bridge(docker0)使用RFC1918私有网络,给每一个container分配ip

设置网络
  通过–net参数来修改container的网络设置,默认是bridge的方式
  none表示关闭container的网路连接
  host表示使用主机的网络栈,这个时候host主机不会创建veth虚拟网卡映射到container

container的网络和主机host的网络在同一网段

# docker run -t --net host saltstack/ubuntu-14.04 sh -c "while true;do ifconfig;sleep 2;done"

DNS
  默认使用host的dns设置
  可以通过–dns的参数来指定container自己的dns配置

端口映射
  docker通过采用端口映射的方式,允许把内部container的服务端口暴露到外包
  使用-p参数可以指定需要暴露的container的内部端口,在不指定特定的host的对应端口的情况下,docker会自动分配(49000-49900)在一个host上的端口与其映射
  使用-P参数,表示暴露所有在image中通过EXPOSE指定的端口

-p 8000:80 -p 443:443:映射容器中的多个端口(前面本机host端口,后面container端口)

volume绑定文件夹映射
  通过-v参数,可以把host上的一个目录绑定到container中,允许container对其进行读写

mkdir /data
[root@docker ~]# docker run -d -v /data:/v-data -h bamboo centos

-v /root/test:/wadeson:将本机host下面的test目录映射到container中下面的wadeson目录
这里是主机的/data隐射到当前容器的/data目录

# 在启动的容器中创建一个文件名为test.txt
sudo docker exec -it  e074fce143e7 /bin/bash cd
[root@bamboo ~]# v-data/
[root@bamboo ~]# touch  test.txt
[root@bamboo ~]# exit

在容器中的data目录实际也对应着本机host的某一处目录,使用inspect查看:

docker inspect e074fce143e7
## 只看我们需要的部分内容如下
"Mounts": [
            {
                "Type": "bind",
                "Source": "/data",
                "Destination": "/v-data",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ]


#回到主机我们可以看到真实目录中也存在这样的文件名
[root@localhost ~]# ls /data
test.txt


Source:对应的是真实主机目录
Destination:容器对应的目录

参考资料
https://www.cnblogs.com/xhyan/p/6235999.html

docker容器常用命令如下:

启动容器:
# docker start mycentos
关闭容器:

# docker stop mycentos 

根据容器ID删除正在运行的容器
docker rm 5e9b198b3dcb      # 删除容器


杀死所有正在运行的容器
docker kill $(docker ps -a -q)

删除所有已经停止的容器
docker rm $(docker ps -a -q)

删除所有镜像
docker rmi $(docker images -q)

强制删除所有镜像,注意和容器删除的差别
docker rmi -f $(docker images -q)

java在docker中的安装

做java环境镜像之前必须先做操作系统,可以从docker的库中用docker pull imagename下载,也可以自己制作镜像

必要条件:
1.已经安装centos镜像
2.已经有centos启动的容器实例
以上步奏在前面的步奏中已经完成,因此目前有一个centos的实例容器名称叫vigilant_tesla

如果在镜像实例中通过exit退出docker环境后我们接下来安装jdk

下载并安装jdk8.0

http://download.oracle.com/
去官网下载到本地之后,使用sftp上传到主机中

下面这种方式存在问题:
这种方法默认是没有同意官方协议的下载,jar包是一个错误的格式,因此无法解压使用。

yum install wget
 
wget http://download.oracle.com/otn-pub/java/jdk/8u171-b11/512cd62ec5174c3487ac17c61aaa89e8/jdk-8u171-linux-x64.tar.gz

[root@localhost ~]# ls
jdk-8u171-linux-x64.tar.gz

宿主机和docker实例之间的文件拷贝

可以用命令【docker cp 文件名称 容器id : 容器下的路径】把相应的安装文件复制到容器中

docker cp ./jdk-8u171-linux-x64.tar.gz vigilant_tesla:/mnt/

通过这个命令就把主机上的jdk文件拷贝到容器实例中的路径/下面了(容器可以不启动)

进入容器

这里使用上面运行的centos镜像

[root@localhost ~]# docker exec -it  vigilant_tesla bash
[root@5f0580926e17 /]# ls mnt/
jdk-8u171-linux-x64.tar.gz

从主机中进入运行中的容器我们才能看到是里面的文件是否存在,可以看到jdk已经进来了。

配置jdk

和在主机中配置模式是一样的,这里直接看命令

[root@5f0580926e17 /]# cd mnt/
[root@5f0580926e17 mnt]# tar -zxvf jdk-8u171-linux-x64.tar.gz 
[root@5f0580926e17 mnt]# ls 
jdk1.8.0_171
[root@5f0580926e17 mnt]# vi ~/.bashrc

配置文件

export JAVA_HOME=/mnt/jdk1.8.0_171
#export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$JAVA_HOME/bin:$PATH

生效

[root@5f0580926e17 mnt]# source ~/.bashrc

至此我们就创建了一个有jdk的容器实例,我们可以把它打包为一个镜像文件。
通过上面的方式我们知道了一个镜像的内容是怎么制作出来的,它需要基本的操作系统,然后是相关的基础文件安装,整个安装过程都是在其他镜像实例的基础上进行的。因此操作起来还是很一个漫长的过程,但是一旦制作成功,我们就可以直接使用制成镜像运行起来,非常方便。

创建新镜像

查看当前正在运行中的容器

[root@localhost ~]# docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
21708d1896bd        tomcat              "catalina.sh run"        2 hours ago         Up 2 hours          0.0.0.0:8080->8080/tcp   tomcat
5f0580926e17        centos              "/bin/sh -c 'while t…"   7 hours ago         Up 6 hours                                   vigilant_tesla

根据容器vigilant_tesla制作一个新的镜像,因为它本身已经包含了centos和java,因此这里我们取名为centos:java

将容器打包成新的镜像命令
docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]

[root@localhost ~]# docker commit     --author "bamboo <zjcjava@163.com>"     --message "java"     vigilant_tesla     centos:java
sha256:8a6ba946d54a5ab4e511ed4317d9ceb4eff50366b0c3595aec6b0a7ba9badcbe

–author 是指定修改的作者,
–message 则是记录本次修改的内容
–vigilant_tesla基于vigilant_tesla的仓库名称
–centos:java仓库名叫centos标签叫java也可以设置为版本号

查看所有本地镜像,可以看到centos的tag为java的已经出现在下方了。

[root@localhost ~]# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos              java                8a6ba946d54a        15 seconds ago      777MB
tomcat              latest              33e02377a00f        2 weeks ago         554MB
nginx               latest              b175e7467d66        2 weeks ago         109MB
centos              latest              e934aafc2206        3 weeks ago         199MB
lwieske/java-8      latest              6e05355899ef        3 months ago        164MB
hello-world         latest              f2a91732366c        5 months ago        1.85kB

可以看到仓库名称为centos标签为java的镜像已经在列表中了。
但是这里不推荐这种方式生成镜像,因为过程太过繁琐,而且每一步都需要自行安装,建议使用Dockerfile直接创建镜像(后面的篇章会讲到),这在后面的章节中讲会重点介绍。
但是这里我们需要知道如何创建一个自己需要的镜像过程,因为Dockerfile其实就是把这个过程全部配置成了命令参数的方式,而后执行构建的,只是节省了中间我们自己敲命令的过程。

docker push: 推送镜像到远程仓库,需要有hub账号和密码,在后面的篇章会讲到
  docker push NAME[:TAG]
  例子:
  docker push hyzhou/ubuntu:3.2.3

tomcat镜像的使用

这里我们直接拉取线上中央仓库的tomcat镜像,不再像上面的方式安装使用,比较上面的步骤还是很繁琐的。
通过这个镜像我们看看它都是什么内容,其实和jdk的内容大同小异,

docker pull tomcat
docker run --name tomcat -p 8080:8080 -d tomcat
docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
21708d1896bd        tomcat              "catalina.sh run"        17 seconds ago      Up 14 seconds       0.0.0.0:8080->8080/tcp   tomcat
5f0580926e17        centos              "/bin/sh -c 'while t…"   4 hours ago         Up 4 hours                                   vigilant_tesla

命令说明:

-p 8080:8080:将容器的8080端口映射到主机的8080端口

进入容器终端模式

 docker exec -it  tomcat bash
 root@21708d1896bd:/usr/local/tomcat# ls
LICENSE  RELEASE-NOTES	bin   include  logs	       temp	work
NOTICE	 RUNNING.txt	conf  lib      native-jni-lib  webapps

可以看到,其实就是把tomcat的文件放在了容器里面,和java的安装方式是一抹一样的。

打开宿主机的端口可以看到容器的服务启动起来了
http://192.168.1.101:8080/

nginx安装映射
https://www.cnblogs.com/jsonhc/p/7767669.html

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值