docker01

1. 容器简介

1.1 什么是Linux容器

容器其实是一种沙盒技术。沙盒像一个集装箱一样把你的应用“装”起来的技术。这样应用与应用之间就因为有了边界而不至于相互干扰;而被装进了集装箱的应用,也可以被方便地搬来搬去。

Linux容器是与系统其他部分隔离开的一系列进程,从另一个镜像运行,并由该镜像提供支持进程所需的全部文件。容器提供的镜像包含了应用的所有依赖项,因而在从开发到测试再到生产的整个过程中,它都具有可移植性和一致性。

img

1.2 容器的基本概念

隔离性:容器在操作系统层面提供了进程、文件系统、网络等资源的隔离,确保每个容器内部的操作不会影响到其他容器或主机系统。

轻量级:与虚拟机不同,容器不需要包含整个操作系统,而是共享主机操作系统的内核。因此,容器的启动速度快,占用的资源少。一般容器以毫秒级启动,而虚拟机是分钟级启动。

可移植性:容器镜像包含应用程序及其依赖的所有软件和库,使得容器可以在任何支持容器运行的环境中运行(例如,开发者的本地机器、测试环境、生产环境等)。

1.3 容器的核心技术实现

Namespaces

  • 提供进程、网络、文件系统等资源的隔离,确保每个容器内的进程只能看到并操作属于该容器的资源。比如:命名空间可以提供一个进程相互隔离的独立网络空间,不同的容器间进程pid可以相同,进程并不冲突影响,但可以共享底层的计算和存储资源。

Cgroups

  • 管理和限制容器使用的资源(如 CPU、内存、磁盘 I/O 等),确保容器不会超出分配的资源。比如给容器A分配4颗CPU,8G 内存,那这个容器最多用这么多的资源。如果内存超过8G ,会启动swap,效率降低,也可能会被调度系统给kill掉。

白话文:Namespace的作用是“隔离”,他让应用进程只能“看到”该Namespace内的“世界”;而Cgroups的作用是“限制”,它给这个“世界”围了一圈看不见的“墙”。如此一来,进程就真的被“装”在了一个于是隔绝的“房间”里。这就是所谓的沙盒!

1.4 容器和虚拟机的区别?

img

传统虚拟技术

虚拟机(virtual machine)就是带环境安装的一种解决方案。

它可以在一种操作系统里面运行另一种操作系统,比如在Windows 系统里面运行Linux 系统。应用程序对此毫无感知,因为虚拟机看上去跟真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件,不需要了就删掉,对其他部分毫无影响。这类虚拟机完美的运行了另一套系统,能够使应用程序,操作系统和硬件三者之间的逻辑不变。

虚拟机的缺点:1 资源占用多 2 冗余步骤多 3 启动慢

容器技术

Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离。有了容器,就可以将软件运行所需的所有资源打包到一个隔离的容器中。容器与虚拟机不同,不需要捆绑一整套操作系统,只需要软件工作所需的库资源和设置。系统因此而变得高效轻量并保证部署在任何环境中的软件都能始终如一地运行。

Docker和传统虚拟化方式的不同之处:

传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。

为什么docker比VM快?

docker有着比虚拟机更少的抽象层。由于docker不需要Hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。

docker利用的是宿主机的内核,而不需要Guest OS。因此,当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。避免引寻、加载操作系统内核比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载Guest OS,这个新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了这个过程,因此新建一个docker容器只需要几秒钟。

2. Docker简介

2.1 Docker是什么

官网:

开发人员通过Docker将他们的想法变为现实

将软件打包为标准化单元,用于开发、装运和部署

容器是一个标准的软件单元,它封装代码及其所有依赖项,以便应用程序从一个计算环境快速可靠地运行到另一个环境。Docker容器镜像是一个轻量级、独立的可执行软件包,包括运行应用程序所需的一切:代码、运行时、系统工具、系统库和设置。

容器镜像在运行时会变成容器,在Docker容器的情况下,镜像在Docker引擎上运行时会成为容器。容器化软件可用于基于Linux和Windows的应用程序,无论基础结构如何,都将始终运行相同的软件。容器将软件与其环境隔离开来,并确保它统一工作,尽管存在差异,例如开发和阶段之间的差异。

2013年,Docker推出了集装箱行业标准。容器是一个标准化的软件单元,允许开发人员将应用程序与其环境隔离,解决“它在我的机器上工作”的难题。对于今天数以百万计的开发人员来说,Docker是构建和共享容器化应用程序的事实标准——从桌面到云。我们正在为开发人员和开发团队构建从代码到云的独特连接体验。

2.2 Docker的目标

docker的主要目标是"Build,Ship and Run any App,Angwhere", 构建,运输,处处运行

  • 构建:做一个docker镜像

  • 运输:docker pull or push

  • 运行:启动一个容器

每一个容器,他都有自己的文件系统rootfs.

3. Docker熟识

3.1 Docker部署及配置

 $ cd /etc/yum.repos.d
 $ wget https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo
 $ sed -i 's#download.docker.com#mirrors.ustc.edu.cn/docker-ce#g' docker-ce.repo
 $ yum -y install docker-ce
 $ systemctl enable --now docker.service

 # 启动nginx:1.21容器,并且后台运行
 $ docker container run -itd  --name webserver01 -p 8080:80 nginx:1.21
     # 参数解释
         -i:让容器的标准输入打开
         -t:分配一个伪终端
         -d:后台启动
         -p: 将宿主机的8080端口映照至容器的80端口
     # 执行命令终端部分回显如下:
 Unable to find image 'nginx:1.21' locally
 1.21: Pulling from library/nginx
 1fe172e4850f: Pull complete
 35c195f487df: Pull complete
 213b9b16f495: Pull complete
 a8172d9e19b9: Pull complete
 f5eee2cb2150: Pull complete
 93e404ba8667: Pull complete
 Digest: sha256:859ab6768a6f26a79bc42b231664111317d095a4f04e4b6fe79ce37b3d199097
 Status: Downloaded newer image for nginx:1.21
 28a074f14de734d565b61d49f8dd1fd005a7da696b381ec3514fe89449ae96b3
 ​
 # 前台运行nginx容器,退出时删除
 $ docker container run -it nginx:1.21
 ​
 docker container run -itd  --name webserver01 -p 80:80 registry.cn-hangzhou.aliyuncs.com/hujiaming/nginx:1.24.0

测试访问:宿主机IP+8080

img

配置镜像加速器

 # 配置镜像加速器
 $ mkdir -p /etc/docker
 $ tee /etc/docker/daemon.json <<-'EOF'
 {
   "registry-mirrors": ["https://kr1xs9ba.mirror.aliyuncs.com"]
 }
 EOF
 $ systemctl daemon-reload
 $ systemctl restart docker
 ​
 # 查看是否生效
 $ docker info |grep -A 3 'Registry Mirrors'

3.2 Docker架构

img

  1. Docker Client(Docker 客户端)

Docker 客户端是用户与 Docker 系统交互的接口。用户通过 CLI 命令(如 docker rundocker build)与 Docker 守护进程通信,发出管理容器的各种指令。

  1. Dockerd(Docker 守护进程)

Dockerd 是 Docker 的核心守护进程,负责处理来自 Docker 客户端的请求。它管理 Docker 容器、镜像、网络和数据卷,并将请求传递给下一级组件(如 Containerd)。通过 gRPC 与 Containerd 通信。

  1. Containerd

Containerd 是一个高级容器运行时,负责管理容器的整个生命周期。它处理容器的创建、执行、挂载存储和网络管理。通过 gRPC 接收 Dockerd 的指令,并进一步传递给 Runc 和 Shim。

  1. Runc

Runc 是一个 CLI 工具,用于根据 Open Container Initiative (OCI) 规范创建和运行容器。Runc 实际上负责执行容器的启动、停止等底层操作。它通过 fork 进程来创建容器。

  1. Shim

Shim 是一个中介程序,在容器与 Containerd 之间提供隔离。当 Runc 启动容器后,Shim 保持容器运行并将 Runc 从系统进程中分离。这样,如果 Containerd 需要重启或崩溃,容器仍然可以继续运行。

3.3 Docker基本指令

 [root@docker-ce ~]# docker version
 ​
 Client: Docker Engine - Community   # 这是社区版本的 Docker 引擎。
  Version:           26.1.1      # Docker 客户端的版本号。
  API version:       1.45        # Docker API 的版本号。Docker引擎通信的接口。
  Go version:        go1.21.9    # Go 版本
  Git commit:        4cf5afa # 编译客户端时使用的 Git 提交哈希值。这是特定构建的唯一标识符。
  Built:             Tue Apr 30 11:51:00 2024    # 客户端的构建时间。
  OS/Arch:           linux/amd64     # 客户端运行的操作系统和架构
  Context:           default     # Docker Context 是 Docker CLI 的配置,允许用户在多个 Docker 主机之间轻松切换。
 ​
 Server: Docker Engine - Community
  Engine:
   Version:          26.1.1
   API version:      1.45 (minimum version 1.24)
   Go version:       go1.21.9
   Git commit:       ac2de55
   Built:            Tue Apr 30 11:49:57 2024
   OS/Arch:          linux/amd64
   Experimental:     false
  
  containerd:    # containerd 是一个容器运行时,负责在宿主机上管理容器的生命周期。
   Version:          1.6.31
   GitCommit:        e377cd56a71523140ca6ae87e30244719194a521
  
  runc:  # runc 是一个 CLI 工具,用于根据 OCI 规范运行容器。
   Version:          1.1.12
   GitCommit:        v1.1.12-0-g51d5e94
  docker-init:
   Version:          0.19.0
   GitCommit:        de40ad0
   
 [root@docker-ce ~]# docker info 
 Client: Docker Engine - Community
  Version:    26.1.1
  Context:    default
  Debug Mode: false
  Plugins:
   buildx: Docker Buildx (Docker Inc.)
     Version:  v0.14.0
     Path:     /usr/libexec/docker/cli-plugins/docker-buildx
   compose: Docker Compose (Docker Inc.)
     Version:  v2.27.0
     Path:     /usr/libexec/docker/cli-plugins/docker-compose
 ​
 Server:
  Containers: 2
   Running: 2    # 正在运行的容器数量,这里是 2。
   Paused: 0     # 暂停的容器数量,这里是 0。
   Stopped: 0    # 停止的容器数量,这里是 0。
  Images: 2      #  Docker 镜像的数量,这里是 2。
  Server Version: 26.1.1     # Docker 服务器的版本号,这里是 26.1.1。
  Storage Driver: overlay2
   Backing Filesystem: xfs   # 底层文件系统,这里是 xfs。
   Supports d_type: true
   Using metacopy: false
   Native Overlay Diff: true
   userxattr: false
  Logging Driver: json-file
  Cgroup Driver: cgroupfs
  Cgroup Version: 1
  Plugins:
   Volume: local
   Network: bridge host ipvlan macvlan null overlay
   Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
  Swarm: inactive
  Runtimes: io.containerd.runc.v2 runc
  Default Runtime: runc
  Init Binary: docker-init
  containerd version: e377cd56a71523140ca6ae87e30244719194a521
  runc version: v1.1.12-0-g51d5e94
  init version: de40ad0
  Security Options:
   seccomp
    Profile: builtin
  Kernel Version: 3.10.0-1160.el7.x86_64
  Operating System: CentOS Linux 7 (Core)
  OSType: linux
  Architecture: x86_64
  CPUs: 2
  Total Memory: 3.84GiB
  Name: docker-ce
  ID: f0bf43f3-cec5-41dd-8c3d-673a340c7237
  Docker Root Dir: /var/lib/docker
  Debug Mode: false
  Experimental: false
  Insecure Registries:
   127.0.0.0/8
  Registry Mirrors:
   https://kr1xs9ba.mirror.aliyuncs.com/ 
  Live Restore Enabled: false

4. Docker镜像管理

4.1 登录官方镜像仓库

链接:https://hub.docker.com/

 # 登录
 [root@docker-ce ~]# docker login
 Log in with your Docker ID or email address to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com/ to create one.
 You can log in with your password or a Personal Access Token (PAT). Using a limited-scope PAT grants better security and is required for organizations using SSO. Learn more at https://docs.docker.com/go/access-tokens/
 ​
 Username: 2364736365@qq.com      
 Password: 
 WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
 Configure a credential helper to remove this warning. See
 https://docs.docker.com/engine/reference/commandline/login/#credentials-store
 ​
 Login Succeeded
 ​
 # 退出
 [root@docker-ce ~]# docker logout

4.2 搜索官方仓库镜像 docker search <image_name>

 [root@docker-ce ~]# docker search nginx | head -3
 NAME                        DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
 nginx                       Official build of Nginx.                        16723     [OK]
 bitnami/nginx               Bitnami nginx Docker Image                      124                  [OK]

img

4.2 获取镜像 docker pull <image_name>:<tag>

 [root@docker-ce ~]# docker pull tomcat:8-jdk8-corretto
 8-jdk8-corretto: Pulling from library/tomcat
 8de5b65bd171: Pull complete
 00e9707b9594: Pull complete
 a4d7141ce82b: Pull complete
 683f96ff9142: Pull complete
 021d0aeb9b5a: Pull complete
 Digest: sha256:5519094808b33f320cb8821e6789ae813d1c71ee3dd03ecc35035fb94be37a3e
 Status: Downloaded newer image for tomcat:8-jdk8-corretto
 docker.io/library/tomcat:8-jdk8-corretto
 ​
 # 查看本地所有镜像
 [root@docker-ce ~]# docker image ls
 REPOSITORY   TAG               IMAGE ID       CREATED                  SIZE
 tomcat       8-jdk8-corretto   6aa794aeaf2e   Less than a second ago   379MB
 nginx        1.21              fa5269854a5e   12 days ago              142MB

4.3 导出镜像 docker image save <image_name>:<tag> >/to/path/<image_name>.tar.gz

 $ docker image save tomcat:8-jdk8-corretto >/opt/docker-images-tar/tomcat-8-jdk-corretto.tar.gz

提示:导出时需要指定镜像的名称和版本,否则再次导入时镜像名称为空

4.4 导入镜像: docker image load -i /to/path/<image_name>.tar.gz

[root@docker-ce ~]# docker image load -i /opt/docker-images-tar/tomcat-8-jdk-corretto.tar.gz
2ce46c79ab58: Loading layer [==================================================>]  171.1MB/171.1MB
adfbec3e67f4: Loading layer [==================================================>]  184.6MB/184.6MB
62ad8969b17a: Loading layer [==================================================>]  3.072kB/3.072kB
693367907f2b: Loading layer [==================================================>]  31.19MB/31.19MB
21dcce1be3e6: Loading layer [==================================================>]  2.048kB/2.048kB
Loaded image: tomcat:8-jdk8-corretto

[root@docker-ce ~]# docker image ls
REPOSITORY   TAG               IMAGE ID       CREATED                  SIZE
tomcat       8-jdk8-corretto   6aa794aeaf2e   Less than a second ago   379MB
nginx        1.21              fa5269854a5e   12 days ago              142MB

4.5 删除镜像

[root@docker-ce ~]# docker image ls
REPOSITORY   TAG               IMAGE ID       CREATED                  SIZE
tomcat       8-jdk8-corretto   6aa794aeaf2e   Less than a second ago   379MB
nginx        1.21              fa5269854a5e   12 days ago              142MB

[root@docker-ce ~]# docker image rmi tomcat:8-jdk8-corretto
Untagged: tomcat:8-jdk8-corretto
Untagged: tomcat@sha256:5519094808b33f320cb8821e6789ae813d1c71ee3dd03ecc35035fb94be37a3e
Deleted: sha256:6aa794aeaf2e3b423640cb6c28c62735c517b5cf0ac2067f1a6ebc4b826adf35
Deleted: sha256:377575e0dcdd8ca0c48ad4bb750fdef5671d7422e5dfac0aa1056afb3ac0391b
Deleted: sha256:cd150b0a9540259ba404d900d5a4decefb51d5d64f912edf71fc4fbdf1b275b6
Deleted: sha256:e18b666124eab8f055392a4bc8dc0dd3f861963b7c872d535a4ad103192b9def
Deleted: sha256:e3469860a4508d511a68fd1d5ed754565b5c922cc3b283d195a56e42b97d7192
Deleted: sha256:2ce46c79ab58cf3d6f9556e9141c0564407a50028040a94bb8a82ab6e33331c2

[root@docker-ce ~]# docker image ls
REPOSITORY   TAG               IMAGE ID       CREATED                  SIZE
nginx        1.21              fa5269854a5e   12 days ago              142MB

删除镜像(删除镜像需要保证没有基于此镜像运行容器,否则需要先删除容器)

4.6 查看镜像详细信息

[root@docker-ce ~]# docker image inspect nginx:1.21
[
    {
        "Id": "sha256:fa5269854a5e615e51a72b17ad3fd1e01268f278a6684c8ed3c5f0cdce3f230b",
        "RepoTags": [
            "nginx:1.21"
        ],
        "RepoDigests": [
            "nginx@sha256:859ab6768a6f26a79bc42b231664111317d095a4f04e4b6fe79ce37b3d199097"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2022-04-20T10:43:12.055940177Z",
        "Container": "3c8758320eb6a5293e75ce1ff5afe91584a72b4ee400792f34985a27673ffbc2",
        "ContainerConfig": {
            "Hostname": "3c8758320eb6",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [	# 容器加载的环境变量
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.21.6",
                "NJS_VERSION=0.7.2",
                "PKG_RELEASE=1~bullseye"
            ],
            "Cmd": [	# 容器的启动命令
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"nginx\" \"-g\" \"daemon off;\"]"
            ],
            "Image": 	# 镜像ID	"sha256:e158bbfdf1201dbc8876232cef4465c5f69c1fd0986f05ee48291a92debc21a0",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": [
                "/docker-entrypoint.sh"
            ],
   ......
   ......
]

4.7 镜像的拉取策略(了解:Kubernetes Pod章节细讲)

在 Docker 中,镜像拉取策略(Image Pull Policy)决定了在启动容器时如何拉取镜像。指定镜像拉取策略可以控制 Docker 是否从注册表中拉取最新的镜像,或者使用本地缓存的镜像。

  1. IfNotPresent(默认策略):

    • 仅当本地不存在指定的镜像时才从注册表中拉取镜像。如果本地已有该镜像,则使用本地镜像。

[root@docker-ce ~]# docker run --pull=ifnotpresent <image_name>:<image_id>
  1. Always

    • 每次启动容器时总是从注册表中拉取镜像,无论本地是否已有该镜像。

    • 适用于需要确保总是使用最新版本镜像的情况,确保容器总是基于最新的镜像版本启动。

[root@docker-ce ~]# docker run --pull=always <image_name>:<image_id>
  1. Never

    • 仅使用本地已有的镜像,从不从注册表中拉取镜像。如果本地不存在指定的镜像,则启动容器会失败。

    • 适用于不希望或无法访问镜像注册表的情况,确保使用本地镜像缓存。

[root@docker-ce ~]# docker run --pull=never <image_name>:<image_id>

4.8 阿里云镜像仓库使用

官网:阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台

# 退出Docker官方镜像仓库
[root@docker-ce ~]# docker logout
Removing login credentials for https://index.docker.io/v1/

# 登录阿里云Docker Registry
[root@docker-ce ~]# docker login --username=aliyun6412327368 registry.cn-hangzhou.aliyuncs.com
用于登录的用户名为阿里云账号全名,密码为开通服务时设置的密码。

# 从Registry中拉取镜像
[root@docker-ce ~]# docker pull registry.cn-hangzhou.aliyuncs.com/hujiaming/jiaming:[镜像版本号]

# 将镜像推送到Registry
[root@docker-ce ~]# docker login --username=aliyun6412327368 registry.cn-hangzhou.aliyuncs.com
[root@docker-ce ~]# docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/hujiaming/jiaming:[镜像版本号]
[root@docker-ce ~]# docker push registry.cn-hangzhou.aliyuncs.com/hujiaming/jiaming:[镜像版本号]

5. 容器的日常管理

# 查看本地所有容器
[root@docker-ce ~]# docker container ls
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

# 启动一个容器
[root@docker-ce ~]# docker run -itd --name webserver -p 80:80 nginx:1.21
1257c74b96d9ebebb34e23844838debb1873d5cec7ae5206551dc2463ca8f94a

# 查看正在运行的容器
[root@docker-ce ~]# docker ps 
CONTAINER ID   IMAGE        COMMAND                   CREATED          STATUS          PORTS                               NAMES
1257c74b96d9   nginx:1.21   "/docker-entrypoint.…"   12 seconds ago   Up 11 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   webserver

# 查看所有的容器包括退出
[root@docker-ce ~]# docker ps -a 

# 查看所有的容器ID包括退出
[root@docker-ce ~]# docker ps -aq

[root@docker-ce ~]# curl -I localhost:80
HTTP/1.1 200 OK
Server: nginx/1.21.5
Date: Sun, 09 Jun 2024 05:32:51 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 28 Dec 2021 15:28:38 GMT
Connection: keep-alive
ETag: "61cb2d26-267"
Accept-Ranges: bytes


# 停止/杀死/重启容器
[root@docker-ce ~]# docker container stop/kill/restart webserver
webserver


[root@docker-ce ~]# docker ps -a
CONTAINER ID   IMAGE        COMMAND                   CREATED              STATUS                     PORTS     NAMES
1257c74b96d9   nginx:1.21   "/docker-entrypoint.…"   About a minute ago   Exited (0) 8 seconds ago             webserver


# 删除指定容器
[root@docker-ce ~]# docker container rm webserver
webserver

# 停止所有的容器(慎用)
[root@docker-ce ~]# docker stop `docker ps -q`

# 删除已经退出的容器(慎用)
[root@docker-ce ~]# docker rm `docker ps -a |grep Exited | awk '{print $1}'`

img

  1. CONTAINER ID:

    • 容器的唯一标识符(ID)。

  1. IMAGE:

    • 容器所使用的 Docker 镜像。

  1. COMMAND:

    • 容器启动时运行的命令。

  1. CREATED:

    • 容器创建的时间。容器是在 35 minutes ago(35 分钟前)创建的。

  1. STATUS:

    • 容器的当前状态和运行时间。状态是 Up 25 minutes,表示容器已经运行了 25 分钟。

  1. PORTS:

    • 容器的端口映射信息。

      • 0.0.0.0:80->80/tcp 表示宿主机的 80 端口映射到容器的 80 端口,使用 TCP 协议。

      • :::80->80/tcp 表示在所有 IPv6 地址上,宿主机的 80 端口映射到容器的 80 端口,使用 TCP 协议。

  1. NAMES:

    • 容器的名称。

这个 Docker 容器使用 nginx:1.21 镜像,在 35 分钟前创建,并已经运行了 25 分钟。它将宿主机的 80 端口映射到容器的 80 端口,容器名称是 webserver

5.2 查看容器的日志

# 查看容器的日志
[root@docker-ce ~]# docker logs -f <容器名称/容器ID>  --tail 1

#或者:
[root@docker-ce ~]# cd /var/lib/docker/containers/<容器id>

img

5.3 查看容器的IP地址

[root@docker-ce ~]# docker inspect <容器名称/容器ID> | grep -i -w "ipaddress"

# 或者
[root@docker-ce ~]# docker inspect --format '{{ .NetworkSettings.IPAddress }}' <容器ID/容器名称>

img

5.4 进入容器的方法

[root@docker-ce ~]# docker container run -itd --name webserver -p 8080:80 nginx:1.21
da5151566915f5acce7cf8cb75e475b1ca69860e7a0b64e33600b9aba2eeda1b

[root@docker-ce ~]# docker container exec -it webserver bash
root@da5151566915:/# ls /etc/nginx/conf.d/
default.conf
root@da5151566915:/# exit
exit

5.5 容器与宿主机间传输文件

# 将容器的文件拷贝至宿主机中
[root@docker-ce ~]# docker cp webserver:/usr/share/nginx/html/index.html  /tmp/
Successfully copied 2.05kB to /tmp/

[root@docker-ce ~]# echo "2401" >  /tmp/index.html

# 宿主机的文件拷贝至容器中
[root@docker-ce ~]# docker cp /tmp/index.html webserver:/usr/share/nginx/html/index.html

5.6 容器的状态(了解,Kubernetes细讲Pod的状态

Created:

  • 容器已经被创建,但尚未启动。此时,容器处于一种待机状态,等待进一步的操作。

Running:

  • 容器正在运行并执行其主要进程。处于此状态的容器可以处理请求和数据。

  • docker ps 可以显示所有正在运行的容器。

Paused:

  • 容器的所有进程被暂停(挂起)。此时,容器的 CPU 资源被释放,但内存等其他资源仍然占用。

  • 你可以通过 docker pause <container_id> 暂停一个容器,并通过 docker unpause <container_id> 恢复它。

Restarting:

  • 容器正在重新启动。通常,这种情况发生在容器配置了自动重启策略时,其进程由于某种原因终止并触发重启。

Exited:

  • 容器的主进程已经停止运行,并且没有自动重启策略,或者重启策略未能触发。容器退出状态码可以通过 docker inspect 命令查看。

  • docker ps -a 可以显示所有包含已退出容器的列表。

Dead:

  • 容器遇到严重问题,无法恢复。通常,这是 Docker 容器处于崩溃状态的标志,需要人工干预来处理这个容器。

5.7 容器的重启策略

略,Kubernetes细讲

5.8 容器重命名(慎用)

# 查看正在运行的容器
[root@docker-ce ~]# docker ps 
CONTAINER ID   IMAGE     COMMAND                   CREATED          STATUS          PORTS                               NAMES
804a660194cc   nginx     "/docker-entrypoint.…"   43 seconds ago   Up 41 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   webserver02

# 修改容器的名称
[root@docker-ce ~]# docker rename webserver02 webserver01

# 查看正在运行的容器名称
[root@docker-ce ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                   CREATED              STATUS              PORTS                               NAMES
804a660194cc   nginx     "/docker-entrypoint.…"   About a minute ago   Up About a minute   0.0.0.0:80->80/tcp, :::80->80/tcp   webserver01

6. Docker数据卷的管理

简介:Docker 存储卷(Volume)是用于将数据从宿主机持久化到容器中的一种机制。存储卷可以在容器之间共享和重用,即使容器被删除,卷中的数据仍然会保留。这样容器就算重启数据依然存在!数据卷是经过特殊设计的目录,同一个数据卷可以只支持多个容器的访问。可以对数据卷里的内容直接进行修改。数据卷的变化不会影像镜像的更新。数据卷会一直存在,即使挂载数据卷的容器已经被删除。

Docker数据卷的三种方式

  • Volumes:

    • Docker 管理宿主机文件系统的一部分(/var/lib/docker/volumes)。保存数据的最佳方式。

  • Bind mounts:

    • 将宿主机的任意位置的文件或者目录挂载到容器中。

  • tmpfs

    • 挂载存储在主机系统的内存中,而不会写入主机的文件系统。如果不希望将数据持久存储在任何位置,可以使用tmpfs,同时避免写入容器可写层提高性能。

img

6.1 挂载时创建卷

[root@docker-ce ~]# mkdir /opt/docker-volumes		
[root@docker-ce ~]# docker rm -f $(docker ps -a -q)

[root@docker-ce ~]# docker container run -itd --name webserver -p 8080:80 -v /opt/docker-volumes/webserver:/usr/share/nginx/html nginx:1.21
5ca2dc75699e71f87f8281c705876eaa9ddc58b1dc39521726f8b85bef4728dd

[root@docker-ce ~]# curl http://localhost:8080
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.21.6</center>
</body>
</html>

[root@docker-ce ~]# echo "hello docker volume" >/opt/docker-volumes/webserver/index.html

[root@docker-ce ~]# curl http://localhost:8080
hello docker volume

6.2 挂载指定volume

volume是Docker官方推荐的持久化方案,默认情况下,volume的存储空间来自于宿主机文件系统中的某个目录,如/var/lib/docker/volumes/,docker系统外的程序无权限修改其中的数据。一个volume可以同时供多个container使用,如果没有container使用volume,其不会自动删除,用户需运行docker volume prune明确删除。

如果用户显式创建volume,则需要给其指定一个名称;如果是隐式创建volume,Docker会自动为其分配一个在宿主机范围内唯一的名字。

docker volume create 创建 volume 时,宿主机目录路径必须以/或~/开头,否则 Docker 会将其当成volume而不是bind mount。

如果容器中的目录不存在,docker会自动创建目录;如果容器中的目录已有内容,docker会使用宿主机上目录的内容覆盖容器目录的内容。

# 创建卷
[root@docker-ce ~]# docker volume create nginx-test01

# 查看卷
[root@docker-ce ~]# docker volume ls 
DRIVER    VOLUME NAME
local     nginx-test01

# 查看卷的详细信息
[root@docker-ce ~]# docker volume inspect nginx-test01
[
    {
        "CreatedAt": "2024-06-11T20:58:55+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/nginx-test01/_data",
        "Name": "nginx-test01",
        "Options": null,
        "Scope": "local"
    }
]

# 查看nginx-test01持久卷的存放位置
[root@docker-ce ~]# ll /var/lib/docker/volumes/nginx-test01/_data/

# 挂载测试卷
[root@docker-ce ~]# docker run  -itd --name webserver03 -p 81:80  -v nginx-test01:/usr/share/nginx/html  nginx:v1.24.0
b97b8e15658b3bca4dc90bdacb9e4e6fdc2933c9797e2b84be0a15d71e10ebb7

# 查看容器的详细信息
[root@docker-ce ~]# docker inspect webserver03
        "Mounts": [
            {
                "Type": "volume",
                "Name": "nginx-test01",
                "Source": "/var/lib/docker/volumes/nginx-test01/_data",
                "Destination": "/usr/share/nginx/html",
                "Driver": "local",
                "Mode": "z",
                "RW": true,
                "Propagation": ""
            }

# 再次查看nginx-test01的数据卷目录
[root@docker-ce ~]# ll /var/lib/docker/volumes/nginx-test01/_data/
总用量 8
-rw-r--r-- 1 root root 497 4月  11 2023 50x.html
-rw-r--r-- 1 root root 615 4月  11 2023 index.html

# 访问容器
[root@docker-ce ~]# curl 172.17.0.3
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

# 修改index.html文件内容
[root@docker-ce ~]# echo "hello volume nginx-test01" >  /var/lib/docker/volumes/nginx-test01/_data/index.html 

# 再次测试
[root@docker-ce ~]# curl 172.17.0.3
hello volume nginx-test01

6.2 Bind Mounts持久化

bind mount持久化方式将宿主机中的文件、目录挂载到容器上,相应文件、目录可以被宿主机读写,也可以被容器读写。

bind mount持久化方式可以将数据存储在宿主机器任何地方,但会依赖宿主机的目录结构,因此不能通过docker CLI直接管理,并且非Docker进程和Docker进程都可以修改。

特点:

    • Docker容器与宿主机耦合过于紧密,移植性较差。

使用场景:

    • container共享宿主机配置文件,如docker将宿主机文件/etc/resolv.conf文件bind mount到容器上,两者会使用相同的DNS服务器。

    • 将宿主机开发环境中的源代码或实验结果共享给容器。例如:你在宿主机上进行一个项目Maven的测试,每次你在宿主机上对Maven项目进行了更改后,容器就可以直接获取更改后的结果

# 创建数据目录
[root@docker-ce ~]# mkdir /app/html -p

# 创建容器并且指定挂载Bind Mounts的卷
[root@docker-ce ~]# docker run -itd --name webserver04 -p 82:80  --mount type=bind,src=/app/html/,dst=/usr/share/nginx/html nginx:v1.24.0

# 查看容器详细信息
[root@docker-ce ~]# docker inspect webserver04
            "Mounts": [
                {
                    "Type": "bind",
                    "Source": "/app/html/",
                    "Target": "/usr/share/nginx/html"
                }
            ],

# 测试访问容器
[root@docker-ce ~]# curl 172.17.0.3
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.24.0</center>
</body>
</html>

# 创建发布文件
[root@docker-ce ~]# echo "hello nginx world" > /app/html/index.html

# 再次测试
[root@docker-ce ~]# curl 172.17.0.3
hello nginx world

6.2.1 bind mount注意事项

  • 宿主机目录路径必须以/或~/开头,否则docker会将其当成是volume 而不是bind mount。

  • 如果宿主机上的目录不存在,docker会自动创建目录(多级的绝对路径好像不行)。

  • 如果容器中的目录不存在,docker会自动创建目录。

  • 如果容器中目录已有内容,那么docker会使用宿主机上目录的内容覆盖容器目录的内容。

6.3 tmpfs mount持久化

tmpfs mount只在Linux主机内存中持久化,是临时性的。当容器停止,tmpfs mount会被移除。

特点:

    • 只能在Linux主机内存中,不会持久化到磁盘。

    • 不支持多容器间共享。

场景:

当启动需要访问这些敏感数据的container或者service时,docker会在宿主机上创建一个tmpfs,然后将敏感数据读出写到tmpfs中,再将tmpfs mount到container中,这样能保证数据安全。当容器停止运行时,则相应的tmpfs也从系统中删除。

# 创建容器并且指定他的卷为tmpfs类型
[root@docker-ce ~]# docker run -itd  \
                       --name webserver05  \
                       --mount type=tmpfs,dst=/usr/share/nginx/html  \
                       nginx:v1.24.0
d8a8122c5eb77e4873866ea33406b7e1ec12eb1ed0ec596bcf6761b78afeacce

# 查看容器的相关信息
[root@docker-ce ~]# docker inspect webserver05
        "Mounts": [
            {
                "Type": "tmpfs",
                "Source": "",
                "Destination": "/usr/share/nginx/html",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }

6.4 存储卷的生命周期管理

# 查看所有volume
[root@docker-ce ~]# docker volume ls

# 查看单个volume详细信息
[root@docker-ce ~]# docker inspect nginx-test01/volume的名称
[
    {
        "CreatedAt": "2024-06-11T20:58:55+08:00",		# 创建时间
        "Driver": "local",		# 卷的驱动类型。local 是默认驱动,表示卷存储在本地宿主机文件系统中。
        "Labels": null,				# 卷的标签,用于标记或组织卷。可以为空或包含键值对。
        "Mountpoint": "/var/lib/docker/volumes/nginx-test01/_data",		# 卷在宿主机上的挂载点,即卷数据存储的路径。
        "Name": "nginx-test01",		# 卷的名称,是在 Docker 中标识这个卷的唯一名称。
        "Options": null,			# 卷的选项,可以用于配置卷的特定行为。可以为空或包含键值对。
        "Scope": "local"			# 卷的作用范围。local 表示该卷仅在创建它的宿主机上可用。
    }
]

# 查看volume是否挂载
[root@docker-ce ~]# docker ps -q | xargs docker inspect --format '{{ .Id }}: {{ .Mounts }}'

# 删除未使用的volume(慎用)
[root@docker-ce ~]# docker volume  prune
WARNING! This will remove anonymous local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Total reclaimed space: 0B

# 删除单个或多个volume
[root@docker-ce ~]# docker volume rm <VOLUME_NAME> <VOLUME_NAME>

7. Docker网络

7.1 Docker网络简介

Docker默认使用桥接模式,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的 Container-IP 直接通信。

Docker网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法直接通过 Container-IP 访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主主机(端口映射),即docker run创建容器时候通过-p参数来启用,访问容器的时候就通过[宿主机IP]:[端口]访问容器。

# 查看网络列表 [root@docker-ce ~]# docker network list NETWORK ID     NAME      DRIVER    SCOPE 6ea2847e7566   bridge    bridge    local 6dc3b646ecc7   host      host      local 8017dbee2836   none      null      local

  • bridge:

    • Docker默认的容器网络驱动。此模式会为每一个容器分配、设置IP等,并将容器连接到一个docker0虚拟网桥,通过docker0网桥以及iptables nat 表配置与宿主机通信。

  • host:

    • 容器与主机共享同一Network Namespace,共享同一套网络协议栈、路由表及iptables规则等。容器与主机看到的是相同的网络视图。

  • Container

    • 创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口。

  • None

    • 容器没有任何网络配置, 完全隔离的网络环境。

7.2 host网络模式配置

相当于Vmware中的桥接模式,与宿主机在同一个网络中,但没有独立IP地址。

Docker使用了Linux的Namespaces技术来进行资源隔离,如PID Namespace隔离进程,Mount Namespace隔离文件系统,Network Namespace隔离网络等。

一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、iptable规则等都与其他的Network Namespace隔离。 一个Docker容器一般会分配一个独立的Network Namespace。 但如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace, 而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡、配置自己的IP等,而是使用宿主机的IP和端口。

img

[root@docker-ce ~]# docker run -itd --name webserver01 --net=host nginx:v1.24.0

[root@docker-ce ~]# docker exec -it webserver01 bash

root@docker-ce:/# hostname  -I
192.168.174.110 172.17.0.1 

7.3 container网络模式配置

该模式指定新创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。 新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。

img

[root@docker-ce ~]# docker run -id --name webserver03 nginx:v1.24.0
6f9927ffd0090d95be1c4d93f278b40dfa8f0319fa4e8105c42a6446c0eba3c6

[root@docker-ce ~]# docker run -itd --name webserver04 --net container:webserver03  registry.cn-hangzhou.aliyuncs.com/hujiaming/tomcat:9.0.89-jdk8

[root@docker-ce ~]# docker exec -it webserver03 bash
root@6f9927ffd009:/# curl  localhost:8080
<!doctype html><html lang="en"><head><title>HTTP Status 404 – Not Found</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 404 – Not Found</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Description</b> The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.</p><hr class="line" /><h3>Apache Tomcat/9.0.89</h3></body></html>

7.4 null网络模式配置

none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。 也就是说,这个Docker容器没有网卡、IP、路由等信息。这种网络模式下容器只有lo回环网络,没有其他网卡。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。

8. Dockerfile自动构建docker镜像

root@e05ec18da21c:/# ls /
bin   dev		   docker-entrypoint.sh  home  lib64  mnt  proc  run   srv  tmp  var
boot  docker-entrypoint.d  etc			 lib   media  opt  root  sbin  sys  usr

这些挂载在容器根目录上、用来为容器进程提供隔离后执行环境的文件系统,就是所谓的“容器镜像”。它还有一个更为专业的名字,叫作:rootfs(根文件系统)。以上是一个最常见的 rootfs,或者说容器镜像,会包括如下所示的一些目录和文件,比如 /bin,/etc,/proc 等等;而你进入容器之后执行的 /bin/bash,就是 /bin 目录下的可执行文件,与宿主机的 /bin/bash 完全不同。正是由于 rootfs 的存在,容器才有了一个被反复宣传至今的重要特性:一致性。

什么是容器的“一致性”呢?

由于云端与本地服务器环境不同,应用的打包过程,一直是最“痛苦”的一个步骤。

但有了容器之后,更准确地说,有了容器镜像(即 rootfs)之后,这个问题被非常优雅地解决了。由于 rootfs 里打包的不只是应用,而是整个操作系统的文件和目录,也就意味着,应用以及它运行所需要的所有依赖,都被封装在了一起。但实际上,一个一直以来很容易被忽视的事实是,对一个应用来说,操作系统本身才是它运行所需要的最完整的“依赖库”。有了容器镜像“打包操作系统”的能力,这个最基础的依赖环境也终于变成了应用沙盒的一部分。这就赋予了容器所谓的一致性:无论在本地、云端,还是在一台任何地方的机器上,用户只需要解压打包好的容器镜像,那么这个应用运行所需要的完整的执行环境就被重现出来了。这种深入到操作系统级别的运行环境一致性,打通了应用在本地开发和远端执行环境之间难以逾越的鸿沟。

不过,这时你可能已经发现了另一个非常棘手的问题:难道我每开发一个应用,或者升级一下现有的应用,都要重复制作一次 rootfs 吗?

比如,我现在用Centos操作系统的 ISO 做了一个 rootfs,然后又在里面安装了 Java 环境,用来部署我的 Java 应用。那么,我的另一个同事在发布他的 Java 应用时,显然希望能够直接使用我安装过 Java 环境的 rootfs,而不是重复这个流程。一种比较直观的解决办法是,我在制作 rootfs 的时候,每做一步“有意义”的操作,就保存一个 rootfs 出来,这样其他同事就可以按需求去用他需要的 rootfs 了。但是,这个解决办法并不具备推广性。原因在于,一旦你的同事们修改了这个 rootfs,新旧两个 rootfs 之间就没有任何关系了。这样做的结果就是极度的碎片化。那么,既然这些修改都基于一个旧的 rootfs,我们能不能以增量的方式去做这些修改呢?这样做的好处是,所有人都只需要维护相对于 base rootfs 修改的增量内容,而不是每次修改都制造一个“fork”。

Docker 在镜像的设计中,引入了层(layer)的概念。也就是说,用户制作镜像的每一步操作,都会生成一个层,也就是一个增量rootfs。

img

第**一部分:只读层。**

它是这个容器的 rootfs 最下面的五层,对应的正是 ubuntu:latest 镜像的五层。可以看到,它们的挂载方式都是只读的(ro+wh,即 readonly+whiteout,至于什么是 whiteout?)。

第二部分:可读写层。 它是这个容器的 rootfs 最上面的一层,它的挂载方式为:rw,即 read write。在没有写入文件之前,这个目录是空的。而一旦在容器里做了写操作,你修改产生的内容就会以增量的方式出现在这个层中。

这个可读写层的作用,就是专门用来存放你修改 rootfs 后产生的增量,无论是增、删、改,都发生在这里。而当我们使用完了这个被修改过的容器之后,还可以使用 docker commit 和 push 指令,保存这个被修改过的可读写层,并上传到 Docker Hub 上,供其他人使用;而与此同时,原先的只读层里的内容则不会有任何变化。这,就是增量rootfs 的好处。

第三部分:Init 层。

它是一个以“-init”结尾的层,夹在只读层和读写层之间。Init 层是 Docker 项目单独生成的一个内部层,专门用来存放 /etc/hosts、/etc/resolv.conf 等信息。

需要这样一层的原因是,这些文件本来属于只读的 Ubuntu 镜像的一部分,但是用户往往需要在启动容器时写入一些指定的值比如 hostname,所以就需要在可读写层对它们进行修改。

可是,这些修改往往只对当前的容器有效,我们并不希望执行 docker commit 时,把这些信息连同可读写层一起提交掉。所以,Docker 做法是,在修改了这些文件之后,以一个单独的层挂载了出来。而用户执行 docker commit 只会提交可读写层,所以是不包含这些内容的。

[root@docker-ce ~]# docker inspect eeb6ee3f44bd | grep -i workdir
                "WorkDir": "/var/lib/docker/overlay2/a98f64963021b19fb2703798c7016f35d15d8f4dcf127f732eb0e38d27ca1583/work"

[root@docker-ce ~]# ls /var/lib/docker/overlay2/a98f64963021b19fb2703798c7016f35d15d8f4dcf127f732eb0e38d27ca1583/diff

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和操作命令;每一条指令构建一层镜像,因此每一条指令的内容,就是描述该层镜像应当如何构建(也就是你要执行的操作命令)。

8.1 Dockerfile指令集

FROM 这个镜像的妈妈是谁?(指定基础镜像)

MAINTAINER 告诉别人,谁负责养它?(指定维护者信息,可以没有)LABLE key=values

RUN 你想让它干啥(在命令前面加上RUN即可)

ADD/COPY 给它点创业资金(COPY文件,会自动解压)

WORKDIR 我是cd,今天刚化了妆(设置当前工作目录)

VOLUME 给它一个存放行李的地方(设置卷,挂载主机目录)

EXPOSE 它要打开的门是啥(指定对外的端口)

CMD 奔跑吧,兄弟!(指定容器启动后的要干的事情)

ENTRYPOINT  容器启动命名

ENV 环境变量

USER 切换用户

8.2 单阶段构建镜像

# 下载基础镜像
[root@docker-ce ~]# docker pull registry.cn-hangzhou.aliyuncs.com/hujiaming/node:16.15.0
16.15.0: Pulling from library/node
85bed84afb9a: Already exists
5fdd409f4b2b: Already exists
fa3069e6cecf: Already exists
4ee16f45eff9: Already exists
2cee68386155: Already exists
0aa7befa4a1b: Already exists
d89fa2ee2a9e: Already exists
fea81c9d708c: Already exists
69c8c6687712: Already exists
Digest: sha256:a6c217d7c8f001dc6fc081d55c2dd7fb3fefe871d5aa7be9c0c16bd62bea8e0c
Status: Downloaded newer image for node:16.15.0
docker.io/library/node:16.15.0

# 创建存放目录
[root@docker-ce ~]# mkdir /opt/docker-images/webserver-vue -p

# 编写Dockerfile
[root@docker-ce ~]# vim /opt/docker-images/webserver/Dockerfile
FROM registry.cn-hangzhou.aliyuncs.com/hujiaming/node:16.15.0

RUN git clone https://gitee.com/mirschao/webserver-vue.git

WORKDIR webserver-vue

RUN npm install

EXPOSE 8080

CMD ["npm", "run", "serve"]

# 切换目录
[root@docker-ce ~]# cd /opt/docker-images/webserver

# 构建镜像
[root@docker-ce webserver]# docker build -t webserver:v1.0 .

# 查看镜像
[root@docker-ce ~]# docker images | grep  -i -w webserver
webserver                                              v1.0              60f727ab4ebe   5 minutes ago   1.05GB

# 运行镜像
[root@docker-ce ~]# docker run -itd --name webserver10 -p 8080:8080  webserver:v1.0

[root@docker-ce ~]# docker ps  | grep  -w webserver10
97e8ab5a7cfb   webserver:v1.0                                                   "docker-entrypoint.s…"   4 minutes ago       Up 4 minutes       0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   webserver10

img

# 拉取基础镜像
[root@docker-ce ~]# docker pull registry.cn-hangzhou.aliyuncs.com/hujiaming/jre:8u211-data

# 拉取项目
[root@docker-ce ~]# git clone https://gitee.com/rulaipo/java-test.git

# 切换目录
[root@docker-ce ~]# cd java-test/
[root@docker-ce java-test]# ls
Dockerfile  spring-cloud-eureka-0.0.1-SNAPSHOT.jar

# 查看Dockerfile
[root@docker-ce java-test]# cat Dockerfile 
# 基础镜像可以按需修改,可以更改为公司自有镜像
FROM registry.cn-hangzhou.aliyuncs.com/hujiaming/jre:8u211-data
# 切换工作目录
WORKDIR /app
# jar 包名称改成实际的名称,本示例为 spring-cloud-eureka-0.0.1-SNAPSHOT.jar
COPY spring-cloud-eureka-0.0.1-SNAPSHOT.jar /app
# 端口
EXPOSE 8761
# 启动 Jar 包
CMD ["java","-jar","spring-cloud-eureka-0.0.1-SNAPSHOT.jar"]

# 构建镜像
[root@docker-ce java-test]# docker build -t java-test:v1.0 .
[+] Building 0.1s (8/8) FINISHED                                                                  docker:default
 => [internal] load build definition from Dockerfile                                                        0.0s
 => => transferring dockerfile: 446B                                                                        0.0s
 => [internal] load metadata for registry.cn-hangzhou.aliyuncs.com/hujiaming/jre:8u211-data                 0.0s
 => [internal] load .dockerignore                                                                           0.0s
 => => transferring context: 2B                                                                             0.0s
 => [1/3] FROM registry.cn-hangzhou.aliyuncs.com/hujiaming/jre:8u211-data                                   0.0s
 => [internal] load build context                                                                           0.0s
 => => transferring context: 62B                                                                            0.0s
 => CACHED [2/3] WORKDIR /app                                                                               0.0s
 => CACHED [3/3] COPY spring-cloud-eureka-0.0.1-SNAPSHOT.jar /app                                           0.0s
 => exporting to image                                                                                      0.0s
 => => exporting layers                                                                                     0.0s
 => => writing image sha256:8975f4ec6299fa9f5679551075aa4235144020ce5826bbd2a5ce5dca63b98a7f                0.0s
 => => naming to docker.io/library/java-test:v1.0                                                           0.0s

# 查看镜像
[root@docker-ce java-test]# docker images | grep java
java-test                                              v1.0              8975f4ec6299   11 minutes ago   174MB

# 启动容器
[root@docker-ce java-test]# docker run -itd --name java-test -p 8761:8761 java-test:v1.0

#查看容器
[root@docker-ce java-test]# docker ps | grep java 
8dcb97455b5d   java-test:v1.0                                                 "java -jar spring-cl…"   9 minutes ago   Up 9 minutes   0.0.0.0:8761->8761/tcp, :::8761->8761/tcp   java-test

测试访问

img

8.3 多阶段构建镜像

# 拉取代码
$ git clone https://github.com/hlions/webserver-vue.git
$ cd webserver-vue
$ cat Dockerfile
FROM registry.cn-hangzhou.aliyuncs.com/hujiaming/node:16.15.0   AS builder
COPY ./ /app
WORKDIR /app
RUN npm install && npm run build

FROM registry.cn-hangzhou.aliyuncs.com/hujiaming/nginx:v1.24.0
RUN mkdir /app
COPY --from=builder /app/dist /app
COPY nginx.conf /etc/nginx/nginx.conf

$ cat nginx.conf
user  nginx;
worker_processes  1;
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;
events {
  worker_connections  1024;
}
http {
  include       /etc/nginx/mime.types;
  default_type  application/octet-stream;
  log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';
  access_log  /var/log/nginx/access.log  main;
  sendfile        on;
  keepalive_timeout  65;
  server {
    listen       80;
    server_name  localhost;
    location / {
      root   /app;
      index  index.html;
      try_files $uri $uri/ /index.html;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
      root   /usr/share/nginx/html;
    }
  }
}

$ docker build -t webserver:v1.1 .

8.4 Dockerfile优化

  1. 多阶段构建镜像

使用多个FROM指令,将构建过程分为多个阶段;每个阶段生成一个独立的镜像,后续阶段可以使用前面阶段生成的镜像作为基础镜像。多阶段构建可以有效减小最终镜像的体积,分离构建环境和运行环境多阶段构建。它允许在一个Dockerfile中使用多个FROM指令,每个FROM指令都可以使用不同的基础镜像,并且每个FROM指令都开始一个新的构建阶段。多阶段构建的主要目的是将构建过程分为多个独立的阶段,每个阶段生成一个独立的镜像。后续阶段可以使用前面阶段生成的镜像作为基础镜像,从而实现构建环境和运行环境的分离,有效减小最终镜像的体积。

  1. 把不需要的命令输出丢入/dev/null

对于某些命令的标准输出和错误输出,如果不需要,可以重定向到/dev/null,避免不必要的输出写入镜像层,减小镜像体积。使用command > /dev/null 2>&1的形式进行重定向

FROM ubuntu:latest
 
RUN apt-get update > /dev/null 2>&1 && \
    apt-get install -y nginx > /dev/null 2>&1 
  1. 使用普通用户运行

在Dockerfile中使用USER指令切换到非root用户,以最小权限原则运行应用,提高安全性。确保应用程序有足够权限访问所需资源

FROM node:14

RUN useradd zhangsan
USER zhangsan
  1. 选择合适的基础镜像

  • Alpine Linux是一个面向安全的轻型Linux发行版,镜像体积小,相比Ubuntu、CentOS等,Alpine Linux更适合作为基础镜像,务必评估Alpine Linux与应用程序的兼容性。

  1. 减少镜像层数

  • 一次RUN指令形成新的一层,尽量Shell命令都写在一行,减少镜像层。

FROM ubuntu:latest
 
RUN apt-get update && \
    apt-get install -y nginx

9. HarBor私有镜像仓库

Harbor 是一个开源的企业级容器镜像仓库,由 VMware 开发并捐赠给 CNCF(Cloud Native Computing Foundation)。它不仅提供了存储和分发 Docker 镜像的基本功能,还增加了很多企业级功能,使得它在安全性、管理性和可扩展性方面表现优异。Docker容器应用的开发和运行离不开可靠的镜像管理。

9.1 安装docker-compose

$ wget https://github.com/docker/compose/releases/download/v2.5.0/docker-compose-linux-x86_64
$ mv docker-compose-linux-x86_64 /usr/local/bin/docker-compose
$ chmod a+x /usr/local/bin/docker-compose
$ docker-compose version
Docker Compose version v2.15.1

9.2 安装Harbor

# 上传安装包
[root@docker-ce opt]# ls
harbor-offline-installer-v2.7.1.tgz  

# 解压安装包
[root@docker-ce opt]# tar xf harbor-offline-installer-v2.7.1.tgz 

# 切换目录
[root@docker-ce opt]# cd harbor

# 拉取harbor所需的镜像
[root@docker-ce harbor]# docker load -i harbor.v2.7.1.tar.gz 

# 修改配置文件
[root@docker-ce harbor]# cp harbor.yml.tmpl  harbor.yml
[root@docker-ce harbor]# vim harbor.yml
...
hostname: harbor.tanke.love
http:
  port: 80
https:
  port: 443
  certificate: /tmp/fullchain.pem
  private_key: /tmp/privkey.pem
harbor_admin_password: 12345
data_volume: /data/harbor
location: /var/log/harbor
...

# 创建数据存放目录
[root@docker-ce harbor]# mkdir /data/harbor -p

# 添加权限
[root@docker-ce harbor]# chmod 777 -R /data/  /var/log/harbor/

# 生成和检查Harbor的配置文件,并确保所有必要的依赖项和环境都已准备就绪。
[root@docker-ce harbor]# ./prepare 
prepare base dir is set to /opt/harbor
Generated configuration file: /config/portal/nginx.conf
Generated configuration file: /config/log/logrotate.conf
Generated configuration file: /config/log/rsyslog_docker.conf
Generated configuration file: /config/nginx/nginx.conf
Generated configuration file: /config/core/env
Generated configuration file: /config/core/app.conf
Generated configuration file: /config/registry/config.yml
Generated configuration file: /config/registryctl/env
Generated configuration file: /config/registryctl/config.yml
Generated configuration file: /config/db/env
Generated configuration file: /config/jobservice/env
Generated configuration file: /config/jobservice/config.yml
Generated and saved secret to file: /data/secret/keys/secretkey
Successfully called func: create_root_cert
Generated configuration file: /compose_location/docker-compose.yml
Clean up the input dir

# 查看镜像
[root@docker-ce harbor]# docker-compose images
CONTAINER           REPOSITORY                    TAG                 IMAGE ID            SIZE
harbor-core         goharbor/harbor-core          v2.7.1              49d6c8a15d6c        215MB
harbor-db           goharbor/harbor-db            v2.7.1              b3f8d9d6c213        174MB
harbor-jobservice   goharbor/harbor-jobservice    v2.7.1              829d13e6aae7        252MB
harbor-log          goharbor/harbor-log           v2.7.1              eeb93d98a358        133MB
harbor-portal       goharbor/harbor-portal        v2.7.1              fe05b1b0bcfd        135MB
nginx               goharbor/nginx-photon         v2.7.1              e98018335c0d        126MB
redis               goharbor/redis-photon         v2.7.1              229dd1844a26        127MB
registry            goharbor/registry-photon      v2.7.1              9d50b10d3700        78.1MB
registryctl         goharbor/harbor-registryctl   v2.7.1              9b2219d529c8        140MB

# 安装和启动 Harbor 的主要安装脚本
[root@docker-ce harbor]# ./install.sh 
[Step 5]: starting Harbor ...
WARN[0000] /opt/harbor/docker-compose.yml: `version` is obsolete 
[+] Running 10/10
 ✔ Network harbor_harbor        Created                                                                     0.1s 
 ✔ Container harbor-log         Started                                                                     0.9s 
 ✔ Container registry           Started                                                                     2.3s 
 ✔ Container registryctl        Started                                                                     1.9s 
 ✔ Container redis              Started                                                                     2.0s 
 ✔ Container harbor-portal      Started                                                                     2.3s 
 ✔ Container harbor-db          Started                                                                     2.3s 
 ✔ Container harbor-core        Started                                                                     2.9s 
 ✔ Container nginx              Started                                                                     4.1s 
 ✔ Container harbor-jobservice  Started                                                                     4.0s 
✔ ----Harbor has been installed and started successfully.----


# 查看启动的容器
[root@docker-ce harbor]# docker-compose ps
NAME                IMAGE                                COMMAND                  SERVICE             CREATED             STATUS                    PORTS
harbor-core         goharbor/harbor-core:v2.7.1          "/harbor/entrypoint.…"   core                11 minutes ago      Up 11 minutes (healthy)   
harbor-db           goharbor/harbor-db:v2.7.1            "/docker-entrypoint.…"   postgresql          11 minutes ago      Up 11 minutes (healthy)   
harbor-jobservice   goharbor/harbor-jobservice:v2.7.1    "/harbor/entrypoint.…"   jobservice          11 minutes ago      Up 11 minutes (healthy)   
harbor-log          goharbor/harbor-log:v2.7.1           "/bin/sh -c /usr/loc…"   log                 11 minutes ago      Up 11 minutes (healthy)   127.0.0.1:1514->10514/tcp
harbor-portal       goharbor/harbor-portal:v2.7.1        "nginx -g 'daemon of…"   portal              11 minutes ago      Up 11 minutes (healthy)   
nginx               goharbor/nginx-photon:v2.7.1         "nginx -g 'daemon of…"   proxy               11 minutes ago      Up 11 minutes (healthy)   0.0.0.0:80->8080/tcp, :::80->8080/tcp, 0.0.0.0:443->8443/tcp, :::443->8443/tcp
redis               goharbor/redis-photon:v2.7.1         "redis-server /etc/r…"   redis               11 minutes ago      Up 11 minutes (healthy)   
registry            goharbor/registry-photon:v2.7.1      "/home/harbor/entryp…"   registry            11 minutes ago      Up 11 minutes (healthy)   
registryctl         goharbor/harbor-registryctl:v2.7.1   "/home/harbor/start.…"   registryctl         11 minutes ago      Up 11 minutes (healthy) 

# 登录镜像仓库
[root@docker-ce harbor]# docker login https://harbor.tanke.love

img

9.3 docker-compose介绍

Docker Compose 是一个用于定义和运行多容器 Docker 应用的工具。通过使用 YAML 文件,你可以配置应用需要的所有服务,然后使用一个命令就能创建并启动这些服务。Docker Compose 非常适合用来管理复杂的应用程序,其中包含多个相互依赖的服务。

9.2 编排启动镜像

 $ vim /opt/docker-compose/wordpress/docker-compose.yaml
 services:
    db:
      image: mysql:5.7
      volumes:
        - /data/db_data:/var/lib/mysql
      restart: always
      environment:
        MYSQL_ROOT_PASSWORD: somewordpress
        MYSQL_DATABASE: wordpress
        MYSQL_USER: wordpress
        MYSQL_PASSWORD: wordpress
    wordpress:
      depends_on:
        - db
      image: wordpress:latest
      volumes:
        - /data/web_data:/var/www/html
      ports: 
        - "8000:80"
      restart: always
      environment:
        WORDPRESS_DB_HOST: db:3306
        WORDPRESS_DB_USER: wordpress
        WORDPRESS_DB_PASSWORD: wordpress
 ​
 $ cd /opt/docker-compose/wordpress
 ​
 # 启动服务
 $ docker-compose up -d
 [+] Running 34/34
  ⠿ wordpress Pulled                                                          181.8s
    ⠿ 1fe172e4850f Already exists                                             0.0s
    ⠿ 012a3732d045 Pull complete                                              37.3s
    ⠿ 43092314d50d Pull complete                                              71.3s
    ⠿ 4f615e42d863 Pull complete                                              71.4s
    ⠿ cd39010a4efc Pull complete                                              72.2s
    ⠿ d983c9ce24de Pull complete                                              72.3s
    ⠿ ecbdd59ae430 Pull complete                                              75.8s
    ⠿ 9d02b88c8618 Pull complete                                              79.5s
    ⠿ 50a246031d43 Pull complete                                              79.6s
    ⠿ a6c0267e6c34 Pull complete                                              84.0s
    ⠿ 787ca6348cef Pull complete                                              91.5s
    ⠿ da8ad43595e2 Pull complete                                              97.4s
    ⠿ e191f9e80e29 Pull complete                                              97.4s
    ⠿ fed8d3fd90f9 Pull complete                                              106.6s
    ⠿ 9ffdaa9000ed Pull complete                                              129.4s
    ⠿ 5774aeca6412 Pull complete                                              129.5s
    ⠿ 6978431bb9e2 Pull complete                                              129.6s
    ⠿ fb4d3fb05351 Pull complete                                              129.7s
    ⠿ 23d3af42839e Pull complete                                              133.6s
    ⠿ a5b33728e4a6 Pull complete                                              133.7s
    ⠿ 766e2b674cd0 Pull complete                                              136.9s
  ⠿ db Pulled                                                                 175.8s
    ⠿ 4be315f6562f Pull complete                                              18.4s
    ⠿ 96e2eb237a1b Pull complete                                              18.5s
    ⠿ 8aa3ac85066b Pull complete                                              18.8s
    ⠿ ac7e524f6c89 Pull complete                                              18.9s
    ⠿ f6a88631064f Pull complete                                              19.0s
    ⠿ 15bb3ec3ff50 Pull complete                                              35.7s
    ⠿ ae65dc337dcb Pull complete                                              35.8s
    ⠿ a4c4c43adf52 Pull complete                                              35.9s
    ⠿ c6cab33e8f91 Pull complete                                              140.1s
    ⠿ 2e1c4f2c43f6 Pull complete                                              140.2s
    ⠿ 2e5ee322af48 Pull complete                                              140.2s
 [+] Running 3/3
  ⠿ Network root_default        Created                                       0.1s
  ⠿ Container root-db-1         Started                                       0.8s
  ⠿ Container root-wordpress-1  Started                                       1.1s
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值