Docker基础篇

一、容器简介

作为一名程序员,无论是开发、测试还是运维,对虚拟机再熟悉不过了,比如常用的VMware属于虚拟机的一种,除此之外还包括VisualBox、Virtual PC等等。虚拟机是具有完整硬件系统功能,运行在完全隔离环境的计算机系统。

虚拟机的优势:在一台物理机上通过虚拟化技术虚拟出多个独立的Guest os。每一个Guest os拥有独立的硬件资源。

缺点:虚拟机占用资源比较多,每个虚拟机都需要os运行的所有硬件资源的虚拟副本。而且有由于添加了一层Hypervisor虚拟化技术,效率也比较低。

大多开发人员都曾经遇到过这种问题:应用部署到本地测试环境没问题,一上生产就各种问题,因为服务器环境、配置的不同排查问题也比较困难。

针对以上问题,加上应用越来越多,给运维带来了很大的工作量,容器时代来临了。容器比虚拟机更轻量,但功能应有尽有。

Docker基础篇_第1张图片

 虚拟机通过Hypervisor对硬件进行虚拟化,容器是直接操作硬件资源,所以容器对资源利用率较高,运行速度更快。同时对于应用需要创建Guest os,而容器只需要启动一个镜像即可。

容器相对于虚拟机:

1)容器启动较快,属于秒级别,虚拟机一般需求几分钟;

2)容器直接与内核交互,占用资源少,效率更快;

3)虚拟机隔离性比较好,所以通常是虚拟机和容器公用;

4)容器在部署,特别是云原生中能够快速交付、快速迭代;

二、Docker基本概述

docker包括镜像、容器、仓库三大部分:

镜像是一个只读联合文件系统,包括容器运行所需的程序、资源、环境、配置。镜像具有分层概念,是将不同层组合成一个文件系统。

下图是一个tomcat镜像,最底层bootfs(boot-file system)包含bootloader和kernel,bootloader主要是加载kernel到内存中,操作系统启动时会加载bootfs文件系统,加载完成后,内存使用权由bootfs交给kernel,然后由系统卸载bootfs。

rootfs基础镜像是在bootfs之上,是不同操作系统的发行版,比如centos、ubuntu;rootfs是精简版的操作系统,所以占用资源比较小。

因为tomcat还依赖于jdk,所以基础镜像上面还需要添加jdk镜像,然后才是tomcat镜像。每一层可以全局公用,比如你本地加载了tomcat镜像,如果再使用jdk无需重新加载,直接使用本地已加载的即可。注意镜像是由镜像名:标签组成,如果不同的标签即不同的版本镜像是不一样的。

Docker基础篇_第2张图片

容器:在镜像上面添加一层可读可写层,如上图,相当于容器=镜像+可读可写层。

仓库:类似Git一样,docker也包括远程仓库和本地仓库,主要是存储镜像。本地构建的镜像也可以push到远程仓库中。

Docker基础篇_第3张图片

docker是C/S结构,用户通过客户端操作docker,docker服务器负载对镜像、容器的操作,客户端可以和服务器部署在一起,也可以通过restful、网络接口与远程docker服务器进行通信交互。

三、常用命令

1、docker卸载

1)卸载docker  Engine, CLI, 和容器包

 $ sudo yum remove docker-ce docker-ce-cli containerd.io

2)删除镜像、容器以及卷

$ sudo rm -rf /var/lib/docker
$ sudo rm -rf /var/lib/containerd

2、docker安装

1)卸载旧版本

$ sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

2)安装需求的软件包

$ sudo yum install -y yum-utils

3)设置镜像仓库

$ sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

建议用国内的

$ sudo yum-config-manager \
    --add-repo \
    http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

4)更新yum软件包,如果是centos8去掉fast

$ yum makecache fast

5)安装Docker CE

$ sudo yum install docker-ce docker-ce-cli containerd.io

6)启动镜像,如果是centos8执行下面命令报错,需要先执行yum erase podman buildah

$ sudo systemctl start(stop、restart) docker

6)测试安装结果

$ docker version
Client: Docker Engine - Community
 Version:           20.10.7
 API version:       1.41
 Go version:        go1.13.15
 Git commit:        f0df350
 Built:             Wed Jun  2 11:56:47 2021
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.7
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       b0f5bc3
  Built:            Wed Jun  2 11:54:58 2021
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.4.6
  GitCommit:        d71fcd7d8303cbf684402823e425e9dd2e99285d
 runc:
  Version:          1.0.0-rc95
  GitCommit:        b9ee9c6314599f1b4a7f497e1f1f856fe433d3b7
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

7)配置镜像加速器

登录阿里云官网找到容器镜像服务,每个用户都有自己的加速器地址

Docker基础篇_第4张图片

 3、docker命令

万能命令docker --help,所有的docker命令都可以通过--help查看。

查看本地镜像信息

root@review:~# docker images
REPOSITORY                  TAG             IMAGE ID       CREATED         SIZE
mysql                       5.7             938b57d64674   2 weeks ago     448MB

搜索远程镜像

root@review:~# docker search mysql
NAME                              DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
mysql                             MySQL is a widely used, open-source relation…   11616     [OK]       

下载远程镜像

root@review:~# docker pull mysql
Using default tag: latest
latest: Pulling from library/mysql
b380bbd43752: Already exists 
f23cbf2ecc5d: Already exists 
30cfc6c29c0a: Already exists 
b38609286cbe: Already exists 
8211d9e66cd6: Already exists 
2313f9eeca4a: Already exists 
7eb487d00da0: Already exists 
4d7421c8152e: Pull complete 
77f3d8811a28: Pull complete 
cce755338cba: Pull complete 
69b753046b9f: Pull complete 
b2e64b0ab53c: Pull complete 
Digest: sha256:6d7d4524463fe6e2b893ffc2b89543c81dec7ef82fb2020a1b27606666464d87
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest

删除本地镜像

root@review:~# docker rmi mysql:latest
Untagged: mysql:latest
Untagged: mysql@sha256:6d7d4524463fe6e2b893ffc2b89543c81dec7ef82fb2020a1b27606666464d87
Deleted: sha256:ecac195d15afac2335de52fd7a0e34202fe582731963d31830f1b97700bf9509
Deleted: sha256:451fe04d80b84c0b7aca0f0bbdaa5de7c7ac85a65389ed5d3ed492f63ac092e2
Deleted: sha256:814cbf8bc7f6bb85685e5b803e16a76406c30d1960c566eee76303ffac600600
Deleted: sha256:735f72e1d1b936bb641b6a1283e4e60bf10a0c36f8244a5e3f8c7d58fa95b98a
Deleted: sha256:f2d209a30c3950fadffb2d82e1faa434da0753bee7aacad9cdec7d8a7a83df37
Deleted: sha256:03b9f8c5331d9534d2372a144bcffc8402e5f7972c9e4b85c634bef203ec6d20

我们可以通过save命令将镜像打包成文件,拷贝给别人使用

docker save -o 保存的文件名 镜像名 eg:docker save -o ./ubuntu.tar ubuntu

在拿到镜像文件后,可以通过load方法,将镜像加载到本地

docker load -i ./ubuntu.tar

启动容器:docker run为启动命令,

-d:后台运行

--name:容器名

-h:进入容器后主机名

--restart always:docker容器重启后,该容器自动启动

-e:设置环境变量

-v:设置数据卷

-p:对外暴露端口

mysql:8:镜像名

$ docker run -d --name mysql-test -h mysql-test --restart always 
-e MYSQL_ROOT_PASSWORD=tiger -e MYSQL_DATABASE='test' 
-v /app/mysql/conf/my.cnf:/etc/mysql/my.cnf -v /data/:/data/ 
-v /data/mysql/data:/var/lib/mysql 
-v /data/mysql/mysql-files:/var/lib/mysql-files/ 
-p 3306:3306 mysql:8

查看容器信息:包括数据挂载、网络、容器其他信息

root@review:~# docker inspect kafka
[
    {
        "Id": "38c54e6e0b5d371afcbb4cf22cea4401f577297668ec5f2ddee0162b01bd0e36",
        "Created": "2021-11-01T07:31:53.437447759Z",
        "Path": "/opt/bitnami/scripts/kafka/entrypoint.sh",
        "Args": [
            "/opt/bitnami/scripts/kafka/run.sh"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 3450,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2021-11-01T07:31:55.149049019Z",
            "FinishedAt": "0001-01-01T00:00:00Z"

docker exec进入一个正在运行的容器

$ docker exec -it 容器名/id /bin/bash(sh)

-i:即使没有连接,也要保持STDIN打开,输入命令后程序会卡住如下图

 但是可以在上面输入查询命令

Docker基础篇_第5张图片

-t:分配一个伪终端,执行下面命令会进入容器中,

在容器中输入命令没有任何反应

 

 输入完整命令后

Docker基础篇_第6张图片

除了docker exec,docker attach也可以进入容器

docker exec和docker attach区别:docker exec在容器内会起一个新的进程,退出的时候不会关闭容器;docker attach直接进入容器启动终端,如果你从两个终端attach到一个container,当你在一个终端输入的时候,内容会出现在另一个终端,两个终端是连接在同一个tty上,所以直接退出的时候会将容器一起关闭,如果想不关闭容器,可以Ctrl+P+Q。

同时,docker run -d mysql启动容器的驻守程序是sshd,docker attact截取的输入输出是该进程(/user/sbin/sshd -D)的。这个进程是不接受输入的,用户无法直接进入容器,所以程序会卡住。

删除容器,rm:删除容器,-f:强制执行

root@review:~# docker rm -f kafka-manager
kafka-manager

启动容器后,如果修改容器中内容可通过docker commit -a="作者" -m="提交说明" 容器id 镜像名:版本,生成新的镜像。

其他命令如下图:Docker基础篇_第7张图片

四、数据卷

docker容器如果关闭,则这个容器被kill掉,容器内的数据一并被清空,为了防止数据丢失,docker通过使用数据卷将数据持久化到宿主机中。

数据卷包括具名数据卷和匿名数据卷,匿名数据卷可以通过docker inspect查看具体位置

Docker基础篇_第8张图片

具名数据卷: docker run -v 名称(不是以/开头):容器路径:ro/rw(ro只读,rw可读可写)

匿名数据卷:docker run -v 容器路径

可以通过docker volume inspect 数据卷名 查看挂载路径

root@review:/app# docker volume inspect zk
[
    {
        "CreatedAt": "2021-11-02T19:20:12+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/zk/_data",
        "Name": "zk",
        "Options": null,
        "Scope": "local"
    }
]

数据卷挂载几种方式:

1)通过docker run -v /宿主机路径:/容器路径

2)通过Dockerfile VOLUME

3)数据卷容器 --volume-from

B容器 --volume-from A容器(A称为数据卷容器,类似于B继承于A),只要有一个容器在,数据就不会丢失

五、Dockerfile

Dockerfile是自动构建镜像的配置文件,简单的讲可以通过Dockerfile文件构建自己的docker镜像,Dockerfile文件是由一组命令组成,命令必须要大写,#为注释。

Dockerfile常用命令:

# 基础镜像,常用的任何镜像都需要一个基础镜像,tag不选,默认为latest
FROM 镜像名:TAG
# 作者信息
MAINTAINER mian [email protected]
# 将本地文件添加到容器中,具有自动解压功能,可以访问网络资源,类似wget
ADD app.jar /
# 功能类似ADD,但是不能自动解压文件,也不能访问网络资源
COPY app.jar /
# 构建镜像时执行的命令
RUN ["yum", "install", "-y", "gcc", "gcc-c++"]
# 设置环境变量
ENV PATH /usr/local/nginx/sbin:$PATH
# 对外暴露端口,可以同时指定多个(只是说明docker容器开放了哪些端口,并没有将这些端口实际开放了出来,需要docker run -p指定)
EXPOSE 8080 443
# 进入容器后指定工作目录,类似于cd
WORKDIR /app
# 设置数据卷,将容器中的数据持久化到本地宿主机
VOLUME ["/opt", "/app"]
# 容器启动的时候执行
CMD ["java", "-jar", "app.jar"]
# 容器启动时执行
ENTRYPOINT ["top"]

ENTRYPOINT与CMD:

相同点:Dockerfile文件只会保留最后一条命令;

不同点:docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT。docker run后面的命令会覆盖CMD中的命令。

 通过docker build构建镜像如果在当前目录后面直接加.

$ docker build -f .(Dockerfile文件的绝对路径)

Docker基础篇_第9张图片

六、容器网络

Docker基础篇_第10张图片

 docker0是docker容器自带的网卡,默认为桥接模式,每开启一个容器都会自动生成一个随机ip。

桥接模式使用的evth-pair技术:就是一对虚拟设备接口,每开启一个容器,会产生一对网卡,一段连接协议,一段彼此相连,正因为这个特性,evth-pair充当一个桥梁,可以连接各种虚拟网络设备。

容器tomcat01和tomcat02之间通过ip是可以ping通的

Docker基础篇_第11张图片

外部访问docker容器网络如下图,通过宿主机网卡直连到docker0网桥,然后访问到具体的应用容器。

Docker基础篇_第12张图片

当容器关闭后,网桥也随之关闭。

由于docker分配的ip都是随机的,需要一个类似不变的服务名代替,如果直接通过服务名是ping不通的,需要添加--link :单向通信,反向是无效的

# 没加--link之前
root@08f58591fa91:/usr/local/tomcat# ping tomcat02
ping: unknown host tomcat02

# 添加--link之后
root@review:~# docker run -d --link tomcat02 --name tomcat01 -p 8085:8080 tomcat:8.0
7308f12982f786796e519e70af48194ef7a04a7915ad092728b292227320ba2b

root@7308f12982f7:/usr/local/tomcat# ping tomcat02
PING tomcat02 (172.17.0.4) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.4): icmp_seq=1 ttl=64 time=0.239 ms
64 bytes from tomcat02 (172.17.0.4): icmp_seq=2 ttl=64 time=0.116 ms
64 bytes from tomcat02 (172.17.0.4): icmp_seq=3 ttl=64 time=0.141 ms

除了上面方式外,可以通过自定义网络进行联通

docker network ls

Docker基础篇_第13张图片

root@review:~# docker network create (--driver bridge) --subnet 192.168.1.0/16 --gateway 192.168.1.1 mynet
d6db3b4e7005a0339988383be574f9fa2c44cdd7a7c19bc4582c91c89c61cdeb
root@review:~# docker network ls
NETWORK ID     NAME              DRIVER    SCOPE
70efc8679b96   bridge            bridge    local
d3bfd3884747   compose_default   bridge    local
f07f88b80132   host              host      local
d6db3b4e7005   mynet             bridge    local
72827e9e4d40   none              null      local

--driver:网络模式,如果不写默认是网桥模式

--subnet:子网地址

--gateway:网关地址

$ docker run -d --name my-nginx --net mynet nginx

docker network connect 网络名 容器名,执行完后相当于在容器中添加一个网络配置

Docker基础篇_第14张图片

创建后,只要在这个网络内的都可以通过服务名进行ping通

root@099b2259faaa:/usr/local/tomcat# ping tomcat02
PING tomcat02 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat02.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.123 ms
64 bytes from tomcat02.mynet (192.168.0.2): icmp_seq=2 ttl=64 time=0.057 ms
64 bytes from tomcat02.mynet (192.168.0.2): icmp_seq=3 ttl=64 time=0.087 ms

root@659f472e242c:/usr/local/tomcat# ping tomcat01
PING tomcat01 (192.168.0.1) 56(84) bytes of data.
64 bytes from tomcat01.mynet (192.168.0.1): icmp_seq=1 ttl=64 time=0.049 ms
64 bytes from tomcat01.mynet (192.168.0.1): icmp_seq=2 ttl=64 time=0.064 ms
64 bytes from tomcat01.mynet (192.168.0.1): icmp_seq=3 ttl=64 time=0.057 ms

 参考文献:【狂神说Java】Docker最新超详细版教程通俗易懂_哔哩哔哩_bilibili

你可能感兴趣的:(docker,容器,运维)