Docker

参考:https://docs.docker.com/engine/install/

安装

image-20240916231218733

参考:https://docs.docker.com/engine/install/

Install using the apt repository 使用apt存储库安装

Before you install Docker Engine for the first time on a new host machine, you need to set up the Docker repository. Afterward, you can install and update Docker from the repository. 在新主机上首次安装Docker Engine之前,需要设置Docker存储库。之后,您可以从存储库安装和更新Docker。

  1. Set up Docker’s apt repository. 设置Docker的apt仓库。

    bash
    # Add Docker's official GPG key:
    sudo apt-get update
    sudo apt-get install ca-certificates curl
    sudo install -m 0755 -d /etc/apt/keyrings
    sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
    sudo chmod a+r /etc/apt/keyrings/docker.asc
    
    # Add the repository to Apt sources:
    echo \
      "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
      $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
      sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    sudo apt-get update

    Note 注意

    If you use an Ubuntu derivative distro, such as Linux Mint, you may need to use UBUNTU_CODENAME instead of VERSION_CODENAME. 如果您使用Ubuntu衍生发行版,例如Linux Mint,则可能需要使用UBUNTU_CODENAME而不是VERSION_CODENAME

  2. Install the Docker packages. 安装Docker包。

    Latest 最新 Specific version 特定版本


    To install the latest version, run: 要安装最新版本,请运行:

    console
    $ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

  3. Verify that the Docker Engine installation is successful by running the hello-world image. 通过运行hello-world镜像来验证Docker Engine安装是否成功。

    console
    $ sudo docker run hello-world

    This command downloads a test image and runs it in a container. When the container runs, it prints a confirmation message and exits. 这个命令下载一个测试映像并在容器中运行它。当容器运行时,它打印一条确认消息并退出。 您现在已经成功安装并启动了Docker Engine。

    sudo systemctl start docker
    sudo systemctl enable docker

配置镜像源:

https://github.com/DaoCloud/public-image-mirror

下载的时候如果配置镜像源失败,可以使用网站前缀加在docker image前面
docker pull docker.1panel.live/library/hello-world
  • Docker 加速

添加到 /etc/docker/daemon.json

{
  "registry-mirrors": [
    "https://docker.m.daocloud.io"
  ]
}

镜像基本命令:

image-20240917005309245

帮助命令

#显示docker版本信息
docker verison
#显示docker详细的信息,包括镜像和容器的数量
docker info
#帮助命令
docker --help

镜像命令

docker images

查看本机所镜像

语法:

docker images -h
Flag shorthand -h has been deprecated, use --help

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

List images

Aliases:
  docker image ls, docker image list, docker images

Options:
  -a, --all             Show all images (default hides intermediate images)
      --digests         Show digests
  -f, --filter filter   Filter output based on conditions provided
      --format string   Format output using a custom template:
                        'table':            Print output in table format
                        with column headers (default)
                        'table TEMPLATE':   Print output in table format
                        using the given Go template
                        'json':             Print in JSON format
                        'TEMPLATE':         Print output using the given
                        Go template.
                        Refer to https://docs.docker.com/go/formatting/
                        for more information about formatting output with
                        templates
      --no-trunc        Don't truncate output
  -q, --quiet           Only show image IDs

image-20240916232027659

解释:

REPOSITORY	镜像的仓库源
TAG			镜像的标签
IMAGE ID	镜像id
CREATED		镜像的创建时间
SIZE		镜像的大小

# 命令可选项
-a,--all 	#列出所有的镜像
-q,--quiet 	#只显示镜像的id

搜索镜像

shell
#可选项
--filter=STARS=3000	# 搜索star大于3000的镜像
docker pull

下载镜像

语法:

docker pull 镜像名[:tag]
shell
C:\Users\maluyao>docker pull mysql
Using default tag: latest #如果不写,默认就是latest
latest: Pulling from library/mysql
5e407bf3af90: Pull complete#分层下载,docker image信息 联合文件系统
5f79c432ce4c: Pull complete
e93edcbaa54f: Pull complete
a0535a79ba39: Pull complete
20ab03fc7bed: Pull complete
75f2fdac1421: Pull complete
f8d6a5d16572: Pull complete
b8dff4a91460: Pull complete
90c257e20398: Pull complete
17219240cf71: Pull complete
Digest: sha256:c69299937e5e2fc9a2cb26f5cd7a7151e48d9d5a3b3679f62bfd1275de698c0c#签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest#真实地址

等价于:
docker pull docker.io/library/mysql:latest

其中

docker.io/library/mysql:latest
就是完整的镜像拉取地址
shell
docker pull -h
Flag shorthand -h has been deprecated, use --help

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

Download an image from a registry

Aliases:
  docker image pull, docker pull

Options:
  -a, --all-tags                Download all tagged images in the repository
      --disable-content-trust   Skip image verification (default true)
      --platform string         Set platform if server is multi-platform
                                capable
  -q, --quiet                   Suppress verbose output
docker rmi

删除镜像

使用语法

shell
docker rmi -h
Flag shorthand -h has been deprecated, use --help

Usage:  docker rmi [OPTIONS] IMAGE [IMAGE...]

Remove one or more images

Aliases:
  docker image rm, 
  docker image remove, 
  docker rmi

Options:
  -f, --force      Force removal of the image	
      --no-prune   Do not delete untagged parents
docker rmi -f 容器id 容器id
docker image

语法:

docker image -h
Flag shorthand -h has been deprecated, use --help

Usage:  docker image COMMAND

Manage images

Commands:
  build       Build an image from a Dockerfile
  history     Show the history of an image
  import      Import the contents from a tarball to create a filesystem image
  inspect     Display detailed information on one or more images
  load        Load an image from a tar archive or STDIN
  ls          List images
  prune       Remove unused images
  pull        Download an image from a registry
  push        Upload an image to a registry
  rm          Remove one or more images
  save        Save one or more images to a tar archive (streamed to STDOUT by default)
  tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE

Run 'docker image COMMAND --help' for more information on a command.

容器命令

我们有了镜像才可以创建容器

docker pull centos

新建容器并启动

docker run [可选参数] image
#参数说明
 --name="Name"	容器名称,用来区分容器
 -d				后台方式运行
 -it			使用交互方式运行,进入容器查看内容
 -p				指定容器的端口		-p 8080:8080
 		-p 主机端口:容器端口	*(常用)
 		-p ip:主机端口:容器端口	(ip是代表主机名)
 		-p 容器端口
 		
 -P				随机指定端口
 

在 Docker 中,-P 参数是用来映射容器内部端口到宿主机随机端口的。当你使用 -P 参数运行容器时,Docker 会随机选择一个宿主机的端口,并将其映射到容器内部开放的网络端口。

下面是对 -P 参数的详细讲解:

  • -P(大写)是告诉 Docker 你想要映射所有暴露的容器端口到宿主机的高位端口(通常是 49153 到 65535 之间的随机端口)。
  • 当你运行一个容器并使用 -P 参数时,比如 docker run -P imagename,Docker 会做以下事情:
    • 查找容器中所有暴露的端口(在 Dockerfile 中使用 EXPOSE 指令指定的)。
    • 对于每个暴露的端口,Docker 会随机选择一个宿主机上的高位端口,并将该宿主机端口映射到容器的端口。
  • 你可以使用 docker container ls 命令来查看端口映射情况。

记住,使用 -P 参数时,由于端口是随机分配的,每次运行容器时宿主机的映射端口都可能不同,这在进行自动化部署或者需要固定端口访问服务时可能会造成不便。在这些情况下,通常推荐使用 -p 参数来指定固定的端口映射。

docker run -it centos 

image-20240916235147521

退出容器

exit			#直接容器停止+退出
ctrl + P + Q	#容器不停止但是退出



[root@48da3f62f358 /]# exit
exit
C:\Users\maluyao>

列出当前正在运行的容器

shell
docker ps
-a		#列出当前正在运行的容器+列出曾经运行过的容器
-n=?	# 列出最近创建的容器
-q		#只显示编号
C:\Users\maluyao>docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

删除容器

docker rm 容器id	#删除指定容器,但是不能删除正在运行中的容器,如果要强制删除,使用-f参数

启动和删除容器的操作

docker start 容器id	#启动容器
docker restart 容器id	#重启容器
docker stop 容器id	#停止当前正在运行的容器
docker kill 容器id	#强制停止当前容器

后台启动容器

image-20240917001057977

# 问题:发现centos停止了
docker容器使用后台运行,就必须要有一个前台进程,docker发现没有应用,就会自动停止
#容器启动后发现自己没有提供服务,就会立刻停止

查看日志

docker logs
C:\Users\maluyao>docker logs --help

Usage:  docker logs [OPTIONS] CONTAINER

Fetch the logs of a container

Aliases:
  docker container logs, docker logs

Options:
      --details        Show extra details provided to logs
  -f, --follow         Follow log output
      --since string   Show logs since timestamp (e.g.
                       "2013-01-02T13:23:37Z") or relative (e.g. "42m"
                       for 42 minutes)
  -n, --tail string    Number of lines to show from the end of the logs
                       (default "all")
  -t, --timestamps     显示时间戳
      --until string   Show logs before a timestamp (e.g.
                       "2013-01-02T13:23:37Z") or relative (e.g. "42m"
                       for 42 minutes)
docker logs -f -t --tail 10 容器id

查看容器中的进程信息

docker top 容器id

查看容器元数据

docker inspect 容器id

进入正在运行中的容器

shell
#我们通常容器都是后台运行的,需要进入容器,修改一些配置
#命令
docker exec -it 容器id bash
#方式二
docker attach 容器id


docker exec		#进入容器之后开启一个新的终端,在里面可以操作(常用)
docker attach	#进入容器正在执行的终端,不会启动新的进程
docker exec 命令的正确格式如下:

docker exec -it 容器id [命令] [参数]
其中:

-it 表示交互式和伪终端(TTY),这允许你与容器的 shell 进行交互。
[命令] 是你希望在容器内运行的命令,例如 bash、sh、python 等。
[参数] 是你想传递给该命令的任何参数。

从容器内拷贝文件到主机上面

dockers cp 容器id:容器内路径 目的主机路径
#拷贝是一个手动过程,未来我们使用 -v卷的家属,可以实现自动同步

实战

nginx

docker run -d --name nginx01 -p 6688:80 nginx

image-20240917011407589

tomcat

#官方的使用
docker run -it --rm tomcat:9.0


#我们之前的部署都是后台,停止容器之后,容器还是可以查到的

--rm	#启动后,用完就删
docker run -d -p 6699:8080 --name tomcat01 78fc74e78f99

网络配置

--net

环境变量

-e

docker stats

查看CPU和内存资源占用情况

可视化

  • portainer(先用这个)
  • Rancher(CI/CD再用)

什么是portainer

Docker图形化界面管理工具!提供一个后台面板供我们操作

shell
docker run -d -p 8088:9000 --restart=always -v \
/var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

commit 镜像

docker commit 提交容器成为一个新的副本
# 命令和git类似
docker commit -m "提交的描述信息" -a="作者" 容器id 目标镜像名[:tag]
提交容器之后,会作为一个镜像存储在本地

容器数据卷

如果数据都在容器中,那么容器删除之后,数据就会丢失

需求:数据可以持久化

容器之间有一个数据共享的技术!Docker容器中产生的数据,同步到本地,这就是卷技术!将我们容器内的目录挂载在;linux上

总结:容器的持久化和同步操作!容器之间可以数据共享

使用数据卷

类似快捷方式,只占用一份存储

方式1:直接使用命令来挂在 -v (volume)

docker run -v 主机目录:容器内目录

实战

安装mysql

安装mysql需要配置密码!
官方测试:
docker run --name mysql01 -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
使用-e MYSQL_ROOT_PASSWORD=my-secret-pw  配置密码

具名挂载和匿名挂载

匿名挂载

-v 容器内路径

docker volume使用

PS C:\Users\maluyao> docker volume --help

Usage:  docker volume COMMAND

Manage volumes

Commands:
  create      Create a volume
  inspect     Display detailed information on one or more volumes
  ls          List volumes
  prune       Remove unused local volumes
  rm          Remove one or more volumes

Run 'docker volume COMMAND --help' for more information on a command.

image-20240917152524440

没有起名字的就是匿名卷

具名挂在
-v 具名:容器内路径
C:\Users\maluyao>docker volume inspect 9b9906de4c81d5ad3fa087d353ec2f2870b9d6650b14a59bb2769ae5fff6cd00
[
    {
        "CreatedAt": "2024-09-16T18:24:04Z",
        "Driver": "local",
        "Labels": {
            "com.docker.volume.anonymous": ""
        },
        "Mountpoint": "/var/lib/docker/volumes/9b9906de4c81d5ad3fa087d353ec2f2870b9d6650b14a59bb2769ae5fff6cd00/_data",
        "Name": "9b9906de4c81d5ad3fa087d353ec2f2870b9d6650b14a59bb2769ae5fff6cd00",
        "Options": null,
        "Scope": "local"
    }
]
所有的docker容器内的卷,没有指定目录的情况下都是在 /var/lib/docker/volumes/卷名/_data下

docker Deskotp工作目录

image-20240917155041304

如何确定是具名挂载还是匿名挂载,还是指定路径挂载!

-v 容器内路径		#匿名挂载
-v 卷名:容器内路径	   #具名挂载
-v /宿主机路径:容器内路径	   #指定路径挂载
在windows使用:
C:\Users\maluyao>docker run -p 9966:80 -d -v E:/log:/log nginx

image-20240917160002555

拓展:

#通过-v 容器内路径,ro,rw
ro	#只读
rw	#可读可写

#一旦设置了容器权限,容器对我们挂载出来的内容就有限定了
C:\Users\maluyao>docker run -p 9966:80 -d -v E:/log:/log:ro nginx
C:\Users\maluyao>docker run -p 9966:80 -d -v E:/log:/log:rw nginx

#看到ro说明这个路径只能宿主机操作,容器内部不能操作

docker inspect命令查看挂载情况

Mounts(挂载)

image-20240918032919947

Volume(卷)

image-20240918033110737

因为nginx是路径挂载,所以没有卷

所有的docker容器内的卷,没有指定目录的情况下都是在 /var/lib/docker/volumes/卷名/_data

Volumes 属性的具体含义如下:

  • 挂载点:这是容器内路径,容器中的应用可以在这个路径下读写数据。
  • 卷的名称:如果卷是由 Docker 自动创建的,则这里会显示 Docker 分配的卷名称。如果卷是由用户指定的宿主机路径,则这里显示的是宿主机的路径。

这里是一个 Volumes 属性的示例:

"Volumes": {
    "/volume01": {},
    "/volume02": {}
}

在这个示例中:

  • "/volume01""/volume02" 是容器内部的挂载点。

  • {} 表示这些卷是由 Docker 自动创建的,它们不在宿主机上有一个明确的路径映射,而是存储在 Docker 的管理空间中。

如果卷是绑定挂载(即指定了宿主机的路径),那么 Volumes 属性看起来会是这样:

"Volumes": {
    "/volume01": "/var/lib/docker/volumes/volume01/_data",
    "/volume02": "/path/on/host"
}

在这个示例中:

  • "/volume01" 是一个自动创建的卷,其数据实际存储在宿主机的 /var/lib/docker/volumes/volume01/_data 路径下。
  • "/volume02" 是一个绑定挂载的卷,其数据存储在宿主机的 /path/on/host 路径下。

例如alist:

image-20240918034245436

使用docker info可以得到

C:\Users\maluyao>docker info
Server:
 Storage Driver: overlay2
  Backing Filesystem: extfs
 Docker Root Dir: /var/lib/docker

输出的内容包含了存储驱动和 docker 根目录的信息。

C:\Users\maluyao>docker run -it --name testDir -v /host_mnt/c/log:/log centos
[root@f05cc548afed /]# ls /log
FRE_Log_20240729.log  FRE_Log_20240801.log  FRE_Log_20240803.log
FRE_Log_20240730.log  FRE_Log_20240802.log  FRE_Log_20240804.log

可以看到/host_mnt/c对应的目录就是主机的C盘

因为这是我把/路径挂载到/msg路径上看到了docker视角下的文件系统

image-20240918175201725

l

Windows 系统中的 Docker

Windows 系统中,Docker 比较复杂,因为有类似于 Linux 容器的原生 Windows 容器,也有运行在基于 Hyper-V 的最小虚拟机中的 Linux 容器。

配置信息和运行 linux 镜像的虚拟机存储在默认的 Docker 根目录。

C:\ProgramData\DockerDesktop

查看常规镜像的信息,会得到 linux 系统中的路径,如:

shell
$ docker inspect nginx

...
"UpperDir": "/var/lib/docker/overlay2/585...9eb/diff"
...

连接镜像:

shell
docker run -it --privileged --pid=host debian nsenter -t 1 -m -u -i sh

现在,可以进入指定路径:

shell
$ cd /var/lib/docker/overlay2/585...9eb/
$ ls -lah

drwx------    4 root     root        4.0K Feb  6 06:56 .
drwx------   13 root     root        4.0K Feb  6 09:17 ..
drwxr-xr-x    3 root     root        4.0K Feb  6 06:56 diff
-rw-r--r--    1 root     root          26 Feb  6 06:56 link
-rw-r--r--    1 root     root          57 Feb  6 06:56 lower
drwx------    2 root     root        4.0K Feb  6 06:56 work

Docker 镜像

最大的文件通常是镜像。如果使用默认的 overlay2 存储驱动,Docker 镜像会保存在 /var/lib/docker/overlay2 目录。

通过一个示例来查看它的内容:

shell
$ docker image pull nginx
$ docker image inspect nginx

[
    {
        "Id": "sha256:207...6e1",
        "RepoTags": [
            "nginx:latest"
        ],
        "RepoDigests": [
            "nginx@sha256:ad5...c6f"
        ],
        "Parent": "",
 ...
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 126698063,
        "VirtualSize": 126698063,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/585...9eb/diff:
                             /var/lib/docker/overlay2/585...9eb/diff",
                "MergedDir": "/var/lib/docker/overlay2/585...9eb/merged",
                "UpperDir": "/var/lib/docker/overlay2/585...9eb/diff",
                "WorkDir": "/var/lib/docker/overlay2/585...9eb/work"
            },
...

初识Dockerfile

Dockerfile就是用来构建docker镜像的构建文件!类似命令脚本

方式二

1、编写dockerfile

image-20240918231957438

2、构建镜像

image-20240918032223615

数据卷容器

--volumes-from

多个mysql同步数据!

shell
#启动多个容器
docker run -it -v log:/log --name docker01 centos
#同步
docker run -it -v log:/log --volumes-from docker01 --name docker02 centos 

下面是效果:

#创建两个容器
C:\Users\maluyao>docker run -it -v log:/log --name docker01 centos
C:\Users\maluyao>docker run -it --volumes-from docker01 --name docker02 centos
#在docker02容器中创建文件
[root@df619632c309 /]# cd log
[root@df619632c309 log]# touch docker02
[root@df619632c309 log]# ls
docker02
#连接docker01发现文件被同步了
C:\Users\maluyao>docker attach docker01
[root@4be578c41a07 /]# ls
bin  dev  etc  home  lib  lib64  log  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@4be578c41a07 /]# ls /log
docker02

--volumes-from就像java的继承机制,继承他挂载的

只是继承卷

DockerFile

dockerfile是用来构建docker镜像的文件!

构建步骤

1、编写dockerfile文件

2、docker buile 构建成为一个镜像

3、docker run 运行镜像

4、docker push发布镜像(docker hub、阿里云)

DockerFile构建过程

很多指令:

image-20240918232153226

VOLUME就是配置挂载路径,哪怕你按照-v后面那样参数的填法一样无法改变

#例如使用VOLUME ["a","/log:/log","log:/etc/log","/ahu"]之后查看容器内绑定:
前面没有 / 的就是相对于工作目录?
"Mounts": [
	{
		"Type": "volume",
		"Name": "b2...",
		"Source": "/var/lib/docker/volumes/b../_data",
		"Destination": "/ahu",
		"Driver": "local",
		"Mode": "",
		"RW": true,
		"Propagation": ""
	},
	{
		"Type": "volume",
		"Name": "7c09..",
		"Source": "/var/lib/docker/volumes/7c../_data",
		"Destination": "/log:/log",
		"Driver": "local",
		"Mode": "",
		"RW": true,
		"Propagation": ""
	},
	{
		"Type": "volume",
		"Name": "813..",
		"Source": "/var/lib/docker/volumes/813../_data",
		"Destination": "a",
		"Driver": "local",
		"Mode": "",
		"RW": true,
		"Propagation": ""
	},
	{
		"Type": "volume",
		"Name": "14d..",
		"Source": "/var/lib/docker/volumes/14d../_data",
		"Destination": "log:/etc/log",
		"Driver": "local",
		"Mode": "",
		"RW": true,
		"Propagation": ""
	}
],

基础知识:

1、每个保留关键字(指令)都是必须(建议,文件忽略大小写)是大写字母

2、执行从上到下顺序执行

3、#表示注释

4、每一个指令都会创建一个新的镜像层,并提交

image-20240918232936336

docker file是面向开发的,我们以后要发布项目,做镜像,就要编写dockerfile文件,这个文件非常简单

docker镜像逐渐成为了企业交付的标准,必须要掌握

FROM		#基础镜像
MAINTAINER	#镜像作者,姓名+邮箱	maintainer(维护员)
RUN			#镜像构建的时候需要运行的命令
ADD			#步骤,制作tomcat镜像就需要添加tomcat的压缩包
WORKDIR		#镜像的工作目录	/ /bin/bash
VOLUME		#挂载到目录
EXPOSE		#指定暴露端口
CMD			#指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT	#指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD		#当构建一个被继承dockerfile这个时候就会执行ONBUILD指令。触发指令
COPY		#类似ADD,将我们的文件拷贝到镜像中
ENV			#构建的时候设置环境变量
LABEL		#官方已经弃用MAINTAINER,推荐使用LABEL

通过命令构建这个文件镜像

docker build -f dockerfile文件路径 -t 镜像名[:tag] .

我们可以使用docker history 镜像名可以列出本地进行的变更历史

image-20240919002043468

docker inspect也可以显示镜像更多信息

CMD和ENTRYPOINT的区别

CMD			#指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT	#指定这个容器启动的时候要运行的命令,可以追加命令

比如:

dockerfile
CMD ["ls","-a"]

#run运行,发现ls -a运行了
#现在想追加一个命令 -l --> ls -al
#cmd的情况下 -l 替换了 CMD ["ls","-a"] 命令,而 -l 不是命令 会直接报错
#entrypoint情况下会直接追加

#下面利用的就是CMD可以被覆盖来进入执行错误的容器,或者迅速执行结束的
E:\>docker run -it mly/tomcat
The JAVA_HOME environment variable is not defined correctly
JAVA_HOME=/usr/locla/jdk1.8.0_401
This environment variable is needed to run this program
NB: JAVA_HOME should point to a JDK not a JRE

E:\>docker run -it mly/tomcat bash
[root@c078b1e5b792 local]# ls /uer/local
ls: cannot access '/uer/local': No such file or directory
[root@c078b1e5b792 local]# ls /usr/local
apache-tomcat-9.0.95  bin  etc  games  include  jdk1.8.0_401  lib  lib64  libexec  sbin  share  src

实战:制作tomcat镜像

1、准备镜像文件 tomcat压缩包,jdk压缩包

image-20240919004610589

2、编写dockerfile文件,官方命名Dockerfile,build会自动寻找这个文件,就不需要-f指定了

dockerfile
FROM centos
MAINTAINER maluyao<1363557207@qq.com>
#使用add命令添加东西会自动解压
ADD jdk-8u401-linux-x64.tar.gz /usr/local
ADD apache-tomcat-9.0.95.tar.gz /usr/local
ENV MYPATH=/usr/local

WORKDIR $MYPATH
ENV JAVA_HOME=/usr/locla/jdk1.8.0_401
ENV CLASSPAYH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME=/usr/local/apache-tomcat-9.0.95
ENV PATH=$PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080
CMD ["catalina.sh","run"]

#"ENV key=value" should be used instead of legacy "ENV key value"
#使用"ENV key=value"来取代"ENV key value"
#只有使用catalina.sh run才是前台启动,而startup.sh和“catalina.sh start”都是后台运行
docker run -it mly/tomcat /bin/bash -c "/usr/local/apache-tomcat-9.0.95/bin/startup.sh && tail -f /usr/local/apache-tomcat-9.0.95/logs/catalina.out"
# 使用bash运行startup.sh脚本,保持在前台运行
CMD /bin/bash /usr/local/apache-tomcat-9.0.95/bin/startup.sh && tail -f /usr/local/apache-tomcat-9.0.95/logs/catalina.out
在这个修改后的CMD指令中,我们做了以下操作:
1、使用/bin/bash来运行startup.sh脚本。

2、使用&&来连接命令,这样在startup.sh脚本执行完毕后,会继续执行tail -f /usr/local/apache-tomcat-9.0.95/logs/catalina.out命令。

3、tail -f命令用于跟踪日志文件的最新内容,并保持在前台运行,防止容器退出。

这样,当容器启动时,startup.sh脚本会被执行,Tomcat会在前台启动,并且tail -f会持续输出Tomcat的日志,从而保持容器运行。

或者拿到一个不输出的前台:
docker run -it mly/tomcat /bin/bash -c "/usr/local/apache-tomcat-9.0.95/bin/startup.sh && bash"
Using CATALINA_BASE:   /usr/local/apache-tomcat-9.0.95
Using CATALINA_HOME:   /usr/local/apache-tomcat-9.0.95
Using CATALINA_TMPDIR: /usr/local/apache-tomcat-9.0.95/temp
Using JRE_HOME:        /usr/local/jdk1.8.0_401
Using CLASSPATH:       /usr/local/apache-tomcat-9.0.95/bin/bootstrap.jar:/usr/local/apache-tomcat-9.0.95/bin/tomcat-juli.jar
Using CATALINA_OPTS:
Tomcat started.
[root@417cf8c0ac29 local]#


#注意问题:这里使用了-c参数来表示cmd,因为&&不能被cmd解析为下一条命令,只是传给构建命令的参数
但是docker run命令本身并不支持-c参数。-c参数是bash shell的选项,用于执行指定的命令字符串,而不是Docker命令的选项。要正确地运行一个CentOS容器并执行bash shell,您应该使用以下命令:
docker run -it centos /bin/bash
Usage:  docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
docker run -it centos /bin/bash
-i:表示交互式操作,保持STDIN打开。
-t:分配一个伪终端。
光加上-t得到一个伪终端,但是没法输入
光加上-i输入命令一直会出问题

image-20240919020843604

使用 docker run -d centos /bin/bash 命令时,您以守护模式(-d)启动了一个容器,并指定了 /bin/bash 作为容器启动时要执行的命令。在这种情况下,容器启动后会执行 /bin/bash,但由于没有提供进一步的命令或脚本供 bash 执行,bash 会立即退出。由于 bash 是容器中的主进程(PID 1),当它退出时,容器也会随之停止。

以下是详细解释:

  • -d:表示以守护模式运行容器,即后台运行。
  • /bin/bash:指定了容器启动时要运行的命令。

当 bash 启动后,它没有接收到任何要执行的命令,因此会立即退出。在容器中,主进程的退出通常会导致容器停止。这就是为什么您看到容器“消失”了——实际上,它是停止了。

如果您想让容器保持运行,您需要确保容器中的主进程持续运行。例如,您可以通过以下几种方式:

  1. 运行一个不会退出的命令或脚本:

    docker run -d centos /bin/bash -c "while true; do echo hello; sleep 1; done"

    在这个例子中,bash 会执行一个无限循环,每秒打印“hello”,因此容器会保持运行。

  2. 运行一个服务,如 sshd:

    docker run -d centos /usr/sbin/sshd -D

    这会启动 sshd 服务,并且容器会保持运行。

  3. 运行一个交互式 shell,但不推荐用于守护进程:

    docker run -itd centos /bin/bash

    虽然这会启动一个交互式 shell,但由于 -d 参数,它会在后台运行。但这不是一个好的实践,因为交互式 shell 在后台运行时通常没有意义。

要正确地让容器以守护模式运行,您应该确保容器中的主进程是设计为持续运行的服务或脚本。

当您使用 docker run -d mly/tomcat /usr/local/apache-tomcat-9.0.95/bin/startup.sh 命令时,您可能在容器启动时执行了 startup.sh 脚本,但是这里存在一个潜在的问题:startup.sh 脚本可能会在启动 Tomcat 后退出,因为它通常会启动 Tomcat 服务作为一个守护进程(后台进程)。

在 Docker 容器中,如果您启动的是一个后台服务(守护进程),那么您需要确保容器中的主进程(PID 1)持续运行。如果主进程退出,Docker 容器会认为没有需要继续运行的进程,因此会停止容器。

startup.sh 脚本可能会启动 Tomcat,但随后脚本本身会退出,导致没有前台进程在运行。这就是为什么容器会自动关闭的原因。

要查看容器的主进程,您需要查看容器的初始进程,这通常是在容器启动时运行的命令。以下是一些查看容器主进程的方法:

  • 在容器外部: 使用 docker top <container_id> 命令可以查看容器内运行的进程。

    bash

    复制

    docker top <container_id>

    这将显示容器内所有进程的列表,包括 PID 为 1 的主进程。

  • 在容器内部: 如果您已经进入了容器,可以通过 ps -ef 命令查看所有进程,包括那些不是当前会话的进程。

    bash

    复制

    ps -ef

    这将显示容器内所有进程的列表,包括后台进程和它们的 PID。

sh-4.4# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 18:13 pts/0    00:00:00 /bin/bash
root        15     0  0 18:18 pts/1    00:00:00 /bin/sh
root        22    15  0 18:20 pts/1    00:00:00 ps -ef

在 Unix 和 Linux 系统中,TTY 代表 “Teletypewriter”,它是用于指代终端设备的一个通用术语。在 ps 命令的输出中,TTY 列显示了进程的控制终端是哪一个。以下是 TTY 的一些常见值及其含义:

  • ?:表示该进程没有控制终端,通常这样的进程是守护进程(daemon)或在后台运行的进程。
  • pts/<number>:表示该进程的控制终端是一个伪终端(pseudo-terminal)。伪终端是网络连接的终端模拟器,常用于远程登录会话,如通过 SSH。
  • tty:表示该进程的控制终端是一个物理终端,如直接连接到计算机的串行端口。
  • console:表示该进程的控制终端是系统控制台

注意

所以-it会生成一个类似ssh的伪终端作为前台,其实没必要写后面的/bin/bash

直接使用docker run -it centos或者docker run -itd centos

光使用一个选项也行docker run -td centosdocker run -id centos

image-20240919024737640

要正确地脱离控制台,您可以使用以下方法:

  1. 使用docker exec命令: 您可以使用docker exec命令来启动一个交互式的终端会话,这样您可以与容器内的Tomcat控制台进行交互,而不会停止容器。

    bash

    复制

    docker exec -it <container_id> /bin/bash

    在这里,<container_id>是您容器的ID。一旦您进入了容器,您就可以像在普通Linux终端中一样使用Ctrl+p+q来脱离控制台,而不会停止容器。

  2. 使用docker logs命令: 如果您只是想要查看Tomcat的日志,可以使用docker logs命令。

    bash

    复制

    docker logs <container_id>

使用他们没有风险,但是如果你使用attach连接到catalina.sh run容器内是,就无法使用快捷键脱离控制台,而且直接关闭窗口会直接结束容器,哪怕你是用tail弄来的前台也没法使用他来脱离

如果-it选项没有同时指定,CTRL-p CTRL-q无法生效

下面其他的方式亲测有用!(我是使用任务管理器杀掉命令终端,这样就不会发送SIGINT信号,一般情况按下退出和ctrl一样都会发送发送SIGINT信号)

其他退出方式 上面两种方式在退出时都有限制,有没有其他方法呢? 1、其实,我们只要另起一个终端,把docker attach进程杀死就可以了

2、如果在docker attach时设置—sig-proxy=false,SIGINT信号不会发送到容器中PID为1的进程,而是被docker attach进程响应,CTRL-c都能退出,但退出的是docker attach进程,容器本身不受影响。

docker attach --sig-proxy=false 8efd

docker exec也不是单纯的连接,而是在运行的容器中执行一个命令,回显命令结果

如果你想保留CMD指令来提供默认参数,应该将其用作用户自定义ENTRYPOINT命令时的附加参数,如下所示:

FROM java:8
COPY *.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]

在这个修改后的Dockerfile中,CMD指令提供了默认的参数--server.port=8080,它将被附加到ENTRYPOINT指令指定的命令后面。当容器启动时,实际运行的命令将是java -jar /app.jar --server.port=8080

因此,中间的CMD ["--server-port=8080"]应该被修改为CMD ["--server.port=8080"],并且参数格式也应该符合Spring Boot应用的实际情况。

3、构建

docker build -t mly/tomcat .

image-20240919015158775

Docker push

先使用docker login登录,然后使用

docker push 镜像名:tag

docker tag

使用docker tag可以给镜像添加标签/改名?
docker tag 原镜像id/镜像名 新镜像名:tag
这会在原来的基础上添加新的,你不会删除原来的,可以借此改名
Usage:  docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
命令别名:
  docker image tag
  docker tag

docker基本命令

基本命令

run从镜像创建并运行一个新的容器。
exec在运行的容器中执行一个命令。
ps列出容器。
build从Dockerfile构建一个镜像。
pull从注册表下载一个镜像。
push将一个镜像上传到注册表。
images列出镜像。
login登录到一个注册表。
logout从一个注册表登出。
search在Docker Hub上搜索镜像。
version显示Docker的版本信息。
info显示系统级别的信息。

docker container

命令中文解释
attach将本地标准输入、输出和错误流附加到一个正在运行的容器上。
commit从容器的更改中创建一个新镜像。
cp在容器和本地文件系统之间复制文件/文件夹。
create创建一个新的容器。
diff检查容器文件系统上文件或目录的更改。
exec在运行的容器中执行一个命令。
export将容器的文件系统导出为tar归档文件。
inspect显示一个或多个容器的详细信息。
kill杀死一个或多个正在运行的容器。
logs获取一个容器的日志。
ls列出容器。
pause暂停一个或多个容器内的所有进程。
port列出端口映射或特定容器的映射。
prune移除所有已停止的容器。
rename重命名一个容器。
restart重启一个或多个容器。
rm移除一个或多个容器。
run从镜像创建并运行一个新的容器。
start启动一个或多个已停止的容器。
stats显示一个或多个容器资源使用统计信息的实时流。
stop停止一个或多个正在运行的容器。
top显示一个容器的运行进程。
unpause解除一个或多个容器内的所有进程的暂停状态。
update更新一个或多个容器的配置。
wait阻塞,直到一个或多个容器停止,然后打印它们的退出码。

docker image

build从Dockerfile构建一个镜像。
history显示一个镜像的历史记录。
import从tarball导入内容以创建一个文件系统镜像。
inspect显示一个或多个镜像的详细信息。
load从tar归档文件或STDIN加载一个镜像。
ls列出镜像。
prune移除未使用的镜像。
pull从注册表下载一个镜像。
push将一个镜像上传到注册表。
rm移除一个或多个镜像。
save将一个或多个镜像保存到tar归档文件(默认情况下通过STDOUT流式传输)。
tag创建一个标签(TARGET_IMAGE),它引用源镜像(SOURCE_IMAGE)。

docker volume

命令中文解释
create创建一个卷。
inspect显示一个或多个卷的详细信息。
ls列出卷。
prune移除未使用的本地卷。
rm移除一个或多个卷。

docker network

connect将一个容器连接到一个网络。
create创建一个网络。
disconnect从一个网络中断开一个容器的连接。
inspect显示一个或多个网络的详细信息。
ls列出网络。
prune移除所有未使用的网络。
rm移除一个或多个网络。

docker update

选项/参数描述
–blkio-weight uint16块 I/O (相对权重), 在 10 和 1000 之间,或 0 以禁用 (默认 0)
–cpu-period int限制 CPU CFS (完全公平调度器) 周期
–cpu-quota int限制 CPU CFS (完全公平调度器) 配额
–cpu-rt-period int限制 CPU 实时周期,以微秒为单位
–cpu-rt-runtime int限制 CPU 实时运行时间,以微秒为单位
-c, —cpu-shares intCPU 份额 (相对权重)
–cpus decimal指定 CPU 数量
–cpuset-cpus string指定允许执行的 CPU 列表 (0-3, 0,1)
–cpuset-mems string指定允许执行的内存列表 (0-3, 0,1)
-m, —memory bytes设置内存限制
–memory-reservation bytes设置内存软限制
–memory-swap bytes设置交换空间限制,等于内存加上交换空间:-1 以启用无限交换
–pids-limit int调整容器 PID 限制 (-1 以启用无限)
–restart string当容器退出时应用的重启策略

这些选项允许你更新 Docker 容器的配置,包括 CPU、内存、I/O、重启策略等。通过这些选项,你可以根据需要调整容器的资源限制,以更好地控制容器的性能和稳定性。

docker save

把镜像变成文件

PS E:\> docker save --help

Usage:  docker save [OPTIONS] IMAGE [IMAGE...]

Save one or more images to a tar archive (streamed to STDOUT by default)

Aliases:
  docker image save, docker save

Options:
  -o, --output string   Write to a file, instead of STDOUT
docker save -o /app.tar fd1685ec0110

打包结果:image-20240920003450809

docker load

PS E:\> docker load --help

Usage:  docker load [OPTIONS]

Load an image from a tar archive or STDIN

Aliases:
  docker image load, docker load

Options:
  -i, --input string   Read from tar archive file, instead of STDIN
  -q, --quiet          Suppress the load output(抑制负载输出)

阿里云存储镜像

1、创建命名空间

image-20240919033305787

2、创建镜像仓库

image-20240919033345922

点击管理可以查看到使用教程 image-20240919033443996

1. 登录阿里云Docker Registry

$ docker login --username=aliyun4527500336 registry.cn-hangzhou.aliyuncs.com

用于登录的用户名为阿里云账号全名,密码为开通服务时设置的密码。

您可以在访问凭证页面修改凭证密码。

2. 从Registry中拉取镜像

$ docker pull registry.cn-hangzhou.aliyuncs.com/maluyao/repo:[镜像版本号]

3. 将镜像推送到Registry

$ docker login --username=aliyun4527500336 registry.cn-hangzhou.aliyuncs.com
$ docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/maluyao/repo:[镜像版本号]
$ docker push registry.cn-hangzhou.aliyuncs.com/maluyao/repo:[镜像版本号]

请根据实际镜像信息替换示例中的[ImageId]和[镜像版本号]参数。

4. 选择合适的镜像仓库地址

从ECS推送镜像时,可以选择使用镜像仓库内网地址。推送速度将得到提升并且将不会损耗您的公网流量。

如果您使用的机器位于VPC网络,请使用 registry-vpc.cn-hangzhou.aliyuncs.com 作为Registry的域名登录。

5. 示例

使用”docker tag”命令重命名镜像,并将它通过专有网络地址推送至Registry。

$ docker imagesREPOSITORY                                                         TAG                 IMAGE ID            CREATED             VIRTUAL SIZEregistry.aliyuncs.com/acs/agent                                    0.7-dfb6816         37bb9c63c8b2        7 days ago          37.89 MB$ docker tag 37bb9c63c8b2 registry-vpc.cn-hangzhou.aliyuncs.com/acs/agent:0.7-dfb6816

使用 “docker push” 命令将该镜像推送至远程。

$ docker push registry-vpc.cn-hangzhou.aliyuncs.com/acs/agent:0.7-dfb6816

Docker网络

理解docker0

  1. 理解Docker的网络模式 在Docker中,网络模式决定了容器如何与主机、其他容器以及外界进行网络通信。以下是几种常见的网络模式:
网络模式描述
bridge默认模式,Docker会创建一个虚拟网络,只在Docker内部可用。
host容器直接使用宿主机的网络堆栈,几乎没有网络隔离。
none不配置任何网络,容器无法访问网络。
container:x让一个容器共享另一个容器的网络

下面是有关docker的网卡,

image-20240919201430069

image-20240919201539362这三个网卡中可以看出来,docker0对应的就是bridge网络配置,一般容器创建时自动使用的就是他

其他两个就是我们创建的桥接,命名都是以br开头的

可以看到我们创建的容器默认是使用docker0的网络配置

image-20240919201858736

通过docker inspect可以查看容器的网络配置

"Networks": {
	"1panel-network": {
		"IPAMConfig": null,
		"Links": null,
		"Aliases": null,
		"MacAddress": "02:42:ac:12:00:02",
		"DriverOpts": null,
		"NetworkID": "75b6...",
		"EndpointID": "da3...",
		"Gateway": "172.18.0.1",
		"IPAddress": "172.18.0.2",
		"IPPrefixLen": 16,
		"IPv6Gateway": "",
		"GlobalIPv6Address": "",
		"GlobalIPv6PrefixLen": 0,
		"DNSNames": [
			"exciting_easley",
			"f3f67a03a6a1"
		]
	}
}
"Networks": {
	"bridge": {
		"IPAMConfig": null,
		"Links": null,
		"Aliases": null,
		"MacAddress": "02:42:ac:11:00:02",
		"DriverOpts": null,
		"NetworkID": "f58fb...",
		"EndpointID": "e757f...",
		"Gateway": "172.17.0.1",
		"IPAddress": "172.17.0.2",
		"IPPrefixLen": 16,
		"IPv6Gateway": "",
		"GlobalIPv6Address": "",
		"GlobalIPv6PrefixLen": 0,
		"DNSNames": null
	}
}

容器互联--link(已启用,不起作用了,原来的作用不需要了)

两个容器要想互相ping通,需要使用ip或者容器名(实际是主机名)或者容器名name
[root@f3f67a03a6a1 /]# ping c411ed6e6201
PING c411ed6e6201 (172.18.0.3) 56(84) bytes of data.
64 bytes from amazing_pascal.1panel-network (172.18.0.3): icmp_seq=1 ttl=64 time=0.119 ms
64 bytes from amazing_pascal.1panel-network (172.18.0.3): icmp_seq=2 ttl=64 time=0.076 ms
但是我们使用--link之后
是在/etc/hosts中添加映射

注意

我是使用自定义网络1panel-network来测试的,他可能自带了容器名称访问

自定义网络

查看所有网络

#docker network ls
NETWORK ID     NAME             DRIVER    SCOPE
75b6c571308d   1panel-network   bridge    local
f58fb70579ff   bridge           bridge    local
230ed53a34f6   host             host      local
1e73eb68649c   mynetwork        bridge    local
e119b7c41336   none             null      local
网络模式描述
bridge默认模式,Docker会创建一个虚拟网络,只在Docker内部可用。
host容器直接使用宿主机共享网络(在此模式下ip与主机完全一致,共享主机的所有网卡)
none不配置任何网络,容器无法访问网络。
container让一个容器共享另一个容器的网络(用的少,局限很大)

测试

使用docker run的时候有个选项叫--ip可以指定ip

—ip string IPv4 address

创建网络:

Usage:  docker network create [OPTIONS] NETWORK

Create a network

Options:
      --attachable           Enable manual container attachment
      --aux-address map      Auxiliary IPv4 or IPv6 addresses used by Network driver
                             (default map[])
      --config-from string   The network from which to copy the configuration
      --config-only          Create a configuration only network
  -d, --driver string        Driver to manage the Network (default "bridge")
      --gateway strings      IPv4 or IPv6 Gateway for the master subnet
      --ingress              Create swarm routing-mesh network
      --internal             Restrict external access to the network
      --ip-range strings     Allocate container ip from a sub-range
      --ipam-driver string   IP Address Management Driver (default "default")
      --ipam-opt map         Set IPAM driver specific options (default map[])
      --ipv6                 Enable or disable IPv6 networking
      --label list           Set metadata on a network
  -o, --opt map              Set driver specific options (default map[])
      --scope string         Control the network's scope
      --subnet strings       Subnet in CIDR format that represents a network segment
 ```
选项:
      --attachable           启用手动容器附加
      --aux-address map      网络驱动程序使用的辅助 IPv4 或 IPv6 地址
                             (默认 map[])
      --config-from string   要复制配置的网络
      --config-only          仅创建配置网络
  -d, --driver string        管理网络的驱动程序(默认 "bridge")
      --gateway strings      主子网的 IPv4 或 IPv6 网关
      --ingress              创建 swarm 路由网格网络
      --internal             限制对网络的外部访问
      --ip-range strings     从子范围分配容器 IP
      --ipam-driver string   IP 地址管理驱动程序(默认 "default")
      --ipam-opt map         设置特定于 IPAM 驱动程序的选项(默认 map[])
      --ipv6                 启用或禁用 IPv6 网络
      --label list           在网络上设置元数据
  -o, --opt map              设置特定于驱动程序的选项(默认 map[])
      --scope string         控制网络的作用域
      --subnet strings       以 CIDR 格式表示网络段的子网
```

注意

使用Windows Docker Desktop网络有问题,下面是主机模式,发现没有和主机有关的网卡(windows和wsl上都没找到!)

image-20240919221315535

使用debian没有遇到这个问题,并且运行成功了

#运行命令
docker run --network host --name dubbo-admin -P -e admin.registry.address=zookeeper://192.168.1.12:2181  -e admin.config-center=zookeeper://192.168.1.12:2181  -e admin.metadata-report.address=zookeeper://192.168.1.12:2181 apache/dubbo-admin

创建network

docker network create --subnet 10.1.0.0/16 --gateway 10.1.0.1 mynet
root@debian:/home/maluyao# docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "5993b0071a56c8146b6e4ca37571163c12374d7a3436047fce42d945fab77859",
        "Created": "2024-09-19T22:31:49.943232771+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "10.1.0.0/16",
                    "Gateway": "10.1.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

好处:

自定义网络可以使用主机名来连接

网络连接:

docker network connect --help

Usage:  docker network connect [OPTIONS] NETWORK CONTAINER

Connect a container to a network

Options:
      --alias strings           Add network-scoped alias for the container
      --driver-opt strings      driver options for the network
      --ip string               IPv4 address (e.g., "172.30.100.104")
      --ip6 string              IPv6 address (e.g., "2001:db8::33")
      --link list               Add link to another container
      --link-local-ip strings   Add a link-local address for the container
连通之后,他是直接将容器加入网络当中
#docker network inspect bridge
 "Containers": {
            "0fd...": {
                "Name": "zookeeper",
                "EndpointID": "3487e7f6cf...",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
#实现一个容器,多个地址

【docker知识】从容器中如何访问到宿主机

一、说明 使用 Docker 能实现服务的容器化,并使用容器间网络在它们之间进行通信。有时您可能需要一个容器来与宿主机上非容器化的服务通信。以下是如何从 Docker 容器中访问本地主机或 127.0.0.1的具体方法。

二、方法1:简单的选择

​ 适用于 Windows 和 Mac 的 Docker Desktop 18.03+ 支持 host.docker.internal 作为 localhost 的功能别名。在您的容器中使用此字符串来访问您的主机。注意,这里区分实体的办法

指定通信个体 别名 解释成容器 localhost或127.0.0.1 解释成主机 host.docker.internal 比如,您在主机上运行 MySQL 服务器,Docker 容器可以通过网络访问连接到主机的mysql 具体名为host.docker.internal:3306 。当您在 Windows 或 Mac 计算机上工作时,这是最简单的技术。

Linux 上的 Docker 引擎用户也可以通过 docker run 的 --add-host 标志启用主机的默认名称 host.docker.internal。使用此标志启动容器以公开主机字符串:

 docker run -d --add-host host.docker.internal:host-gateway my-container:latest

​ —add-host 标志向容器的 /etc/hosts 文件添加一个条目。上面显示的值将 host.docker.internal 映射到容器的主机网关,这与真实的 localhost 值相匹配。如果您愿意,可以用您的主机真实名称替换 host.docker.internal 。

三、方法2:连接到主机网络

​ Docker 提供了一个主机网络,让容器可以共享主机的网络堆栈。这种方法意味着容器内的本地主机解析为物理主机,而不是容器本身。

    通过添加 --network=host 标志与主机网络一起启动容器:
docker run -d --network=host my-container:latest
    现在您的容器可以直接引用本地主机或 127.0.0.1。
    如果您使用的是 Docker Compose,请修改容器的服务定义以包含 network_mode 字段:
services:
  my-service:
    network_mode: host

​ 这种方法有几个注意事项。在使用它之前考虑所有的影响很重要。容器通常会获得自己的私有网络,该网络独立于主机的堆栈。来自主机的设置。

容器公开的任何端口都将在主机上公开,即使它们没有使用 -p 标志明确声明。

主机网络可能是一个安全问题,它打破了 Docker 容器的隔离模型。在您确信正在运行的容器不会相互冲突或导致主机环境出现问题的情况下,它仍然很有用。主机网络模式也比默认桥接模式更快,因为没有供流量通过的虚拟化层。

四、方法3:使用默认桥接模式访问主机

​ 您的主机仍然可以在默认桥接网络模式下从容器访问。您只需要通过其 Docker 网络 IP 引用它,而不是 localhost127.0.0.1

大多数 Docker 引擎安装会将主机表示为默认 docker0 桥接网络上的 172.17.0.1。您可以通过在主机上运行以下命令来检查自己的 IP:

ip addr show docker0

​ 您的主机的 Docker IP 将显示在 inet 行上。从您的容器中连接到此 IP 地址以成功访问在您的主机上运行的服务。

这种方法的一个缺陷是您可能无法连接到直接绑定到本地主机的服务。您会在容器中看到连接被拒绝或类似错误。

windows版本中就是会有一个适配器

image-20250427211216834

同属于一个局域网

image-20250427211307917

五、总结

​ 当您需要从 Docker 容器外部访问机器的本地主机时,您有多种选择。如果您使用的是 Windows 或 Mac,最好使用内置的 host.docker.internal 别名。Linux 用户可以设置类似的东西在启动容器时使用 —add-hostflag。

主机网络模式是一种通用的替代方案,它允许容器共享主机的网络堆栈。您可以直接引用本地主机,但需要了解风险和限制。当需要强大的网络隔离时,这不是一个合适的选择。

坚持使用桥接模式可能是支持它的工作负载的最佳选择。将主机的服务绑定到它的 Docker IP,然后使用该地址从容器内部进行连接。这使您可以使用 Docker 的每个容器虚拟化网络,同时提供一个路由到你的主机在需要的时候。

–-restart=always自动启动容器

springboot打包镜像

Dockers Compose

Docker Swarm

CI/CD Jenkins 流水线

深入探究docker attach的退出方式

docker attach可以将当前终端的标准输入、标准输出和标准错误连接到指定的容器中,可以显示容器 ENTRYPOINT/CMD 进程的输出,是容器调试的重要方法。docker attach之后退出的方法,主要有CTRL-c和CTRL-p CTRL-q两种。大部分说法中,认为CTRL-c会导致容器退出,推荐使用CTRL-p CTRL-q方法。我在实际使用中,发现这些说法并不准确,这两种方法都会收到docker run和docker attach命令选项的影响。

1. CTRL-c方式

与普通的进程一样,docker attach之后执行CTRL-c会发送SIGINT信号。 docker attach命令有—sig-proxy选项,man docker attach中对该选项描述如下:

--sig-proxy=``true``|``false``  ``Proxy all received signals to the process (non-TTY mode only). SIGCHLD, SIGKILL, and SIGSTOP are not proxied. The default is ``true``.

可以看到,该选项仅在non-TTY模式下起作用,即docker run时不指定-t选项。此时,默认—sig-proxy为true,SIGINT信号被发送至docker中PID为1的进程。

doujl@ubuntu:~$ docker run -id centos:7 /bin/bash
edfe9bc8ae02567ff9309ffb6940a9772f02a18d24e4cf04a9da8c84c01e1f52
doujl@ubuntu:~$ docker attach edfe
^C^C^C
doujl@ubuntu:~$ docker run -d centos:7 top -b
8700417c309d1b6c8e3a1618f38b232e8eddedae20287e73f2022b0cac716248
doujl@ubuntu:~$ docker attach 8700
top - 02:37:24 up 19 days,  1:59,  0 users,  load average: 0.94, 1.03, 1.17
Tasks:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
%Cpu(s): 10.4 us,  2.0 sy,  0.0 ni, 87.2 id,  0.3 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  8066788 total,   752956 free,  3659576 used,  3654256 buff/cache
KiB Swap:  8282108 total,  7576840 free,   705268 used.  3378516 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    1 root      20   0   51780   3576   3132 R   0.0  0.0   0:00.04 top^C
doujl@ubuntu:~$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                        PORTS               NAMES
8700417c309d        centos:7            "top -b"            11 seconds ago      Exited (0) 3 seconds ago                          pensive_brahmagupta

上面两个例子中,docker run没有-t选项,docker attach中—sig-proxy默认为true,将信号发送至容器(SIGCHLD,SIGKILL,SIGSTOP除外)。因此SIGINT发送至PID为1的进程,分别为/bin/bash和top -b。第一个例子,/bin/bash没有处理SIGINT信号(加上-i是为防止进程退出)。第二个例子中,top -b响应了SIGINT信号并退出,因此容器退出。

如果在docker attach时设置—sig-proxy=false,SIGINT信号不会发送到容器中PID为1的进程,而是被docker attach进程响应

doujl@ubuntu:~$ docker run -id centos:7 /bin/bash
5a6d97406a068b1a58b02d4b3267a974b8c69e268d37db19b44b2858b5086e0f
doujl@ubuntu:~$ docker attach --sig-proxy=false 5a6d
^C
doujl@ubuntu:~$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
5a6d97406a06        centos:7            "/bin/bash"         11 seconds ago      Up 9 seconds                                    reverent_goldstine
doujl@ubuntu:~$ docker run -d centos:7 top -b
37a80db8bf8f8c79bbb910353d04a46697ad54c0bcb4f34f4ef8edd42163d152
doujl@ubuntu:~$ docker attach --sig-proxy=false 37a8
top - 02:42:45 up 19 days,  2:04,  0 users,  load average: 0.58, 0.74, 0.99
Tasks:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
%Cpu(s):  8.2 us,  1.7 sy,  0.0 ni, 90.1 id,  0.1 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  8066788 total,   782360 free,  3642612 used,  3641816 buff/cache
KiB Swap:  8282108 total,  7576848 free,   705260 used.  3405820 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    1 root      20   0   51780   3668   3224 R   0.0  0.0   0:00.06 top^C
doujl@ubuntu:~$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
37a80db8bf8f        centos:7            "top -b"            15 seconds ago      Up 13 seconds                           tender_kirch

上面两个例子中,CTRL-c都能退出,但退出的是docker attach进程,容器本身不受影响。

以上的例子中,docker run都没有-t选项,如果指定了-t选项呢?

doujl@ubuntu:~$ docker run -itd centos:7 /bin/bash
4ff1e8d42537115f46c98eeae6c1554b388cd3322039f8185bb4e3a1848ec519
doujl@ubuntu:~$ docker attach 4ff1
[root@4ff1e8d42537 /]# ^C
[root@4ff1e8d42537 /]# ^C
[root@4ff1e8d42537 /]# 
doujl@ubuntu:~$ docker run -td centos:7 /bin/bash
7a8f3c2ba41b5b4c047dfe4b9d41774cb6972e1e969b38636affd39920b83b2f
doujl@ubuntu:~$ docker attach 7a8f
[root@7a8f3c2ba41b /]# ^C
doujl@ubuntu:~$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
7a8f3c2ba41b        centos:7            "/bin/bash"         18 seconds ago      Up 17 seconds                           peaceful_bose
doujl@ubuntu:~$ docker run -itd centos:7 top -b
829a0f9c9ac70147783d3db9674def5c2179059956923a1d59ccd8a33f339b37
doujl@ubuntu:~$ docker attach 829a
top - 02:49:10 up 19 days,  2:10,  0 users,  load average: 0.55, 0.72, 0.91
Tasks:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
%Cpu(s): 11.5 us,  2.3 sy,  0.0 ni, 86.2 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  8066788 total,   757280 free,  3659324 used,  3650184 buff/cache
KiB Swap:  8282108 total,  7576884 free,   705224 used.  3384468 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    1 root      20   0   51780   3584   3140 R   0.0  0.0   0:00.05 top

top - 02:49:10 up 19 days,  2:10,  0 users,  load average: 0.55, 0.72, 0.91
Tasks:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  8066788 total,   757280 free,  3659324 used,  3650184 buff/cache
KiB Swap:  8282108 total,  7576884 free,   705224 used.  3384468 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    1 root      20   0   51780   3584   3140 R   0.0  0.0   0:00.05 top^C
doujl@ubuntu:~$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
829a0f9c9ac7        centos:7            "top -b"            12 seconds ago      Exited (0) 2 seconds ago                       angry_yonath
doujl@ubuntu:~$ docker run -td centos:7 top -b
79cfe842cfba1b211dea37fafbc5676c9da2ad6e186f261cccee4098ee1dd02a
doujl@ubuntu:~$ docker attach 79cf
top - 02:50:02 up 19 days,  2:11,  0 users,  load average: 0.33, 0.63, 0.87
Tasks:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
%Cpu(s): 10.3 us,  2.8 sy,  0.0 ni, 86.8 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  8066788 total,   749208 free,  3659560 used,  3658020 buff/cache
KiB Swap:  8282108 total,  7576884 free,   705224 used.  3376832 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    1 root      20   0   51780   3636   3192 R   0.0  0.0   0:00.05 top

top - 02:50:02 up 19 days,  2:11,  0 users,  load average: 0.33, 0.63, 0.87
Tasks:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  8066788 total,   749208 free,  3659560 used,  3658020 buff/cache
KiB Swap:  8282108 total,  7576884 free,   705224 used.  3376832 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    1 root      20   0   51780   3636   3192 R   0.0  0.0   0:00.05 top^C
doujl@ubuntu:~$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
79cfe842cfba        centos:7            "top -b"            9 seconds ago       Up 7 seconds                            loving_ride

可以看到,docker run指定-t选项时,是否指定-i选项也会对docker attach命令有影响。指定-i选项时,SIGINT信号发送到了容器中PID为1的进程,不指定时,信号被docker attach接收。注意,此时docker attach的—sig-proxy选项不起作用。 综上,docker attach后执行CTRL-c会发送SIGINT信号,而信号的接收方会受到docker run的-i、-t选项,和docker attach的—sig-proxy选项影响。

2. CTRL-p CTRL-q方式

CTRL-p CTRL-q方式比较简单,只需要注意docker run时要同时指定-it选项。该方式只会退出docker attach,对容器没有影响

doujl@ubuntu:~$ docker run -itd centos:7 /bin/bash
e73e04370cee90497783a621fd4a044ca196dc419c06a01bae5a4b116d7afc4e
doujl@ubuntu:~$ docker attach e73e#执行CTRL-p CTRL-q
[root@e73e04370cee /]# doujl@ubuntu:~$
doujl@ubuntu:~$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
e73e04370cee        centos:7            "/bin/bash"         44 seconds ago       Up 42 seconds                           vibrant_archimedes

如果-it选项没有同时指定,CTRL-p CTRL-q无法生效

  1. 其他退出方式

上面两种方式在退出时都有限制,有没有其他方法呢? 其实,我们只要另起一个终端,把docker attach进程杀死就可以了

#终端1中执行,没有同时指定-it,CTRL-p CTRL-q无法退出doujl@ubuntu:~$ docker run -id centos:7 /bin/bash00c031965cb2075643e15a3b88141026e753a79e8b03b960880d505950488014doujl@ubuntu:~$ docker attach 00c0
^P
/bin/bash: line 1: $'\020': command not found
^P
#终端2中杀死docker attach进程doujl@ubuntu:~/dettach$ pkill -9 -f 'docker.*attach'
doujl@ubuntu:~/dettach$ 
#终端1中,docker attach已退出
/bin/bash: line 2: $'\020': command not found
已杀死
doujl@ubuntu:~$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
00c031965cb2        centos:7            "/bin/bash"         About a minute ago   Up About a minute                       trusting_meitner

参考文档:

  1. man docker attach
  2. https://docs.docker.com/engine/reference/commandline/attach/
  3. https://stackoverflow.com/questions/25267372/correct-way-to-detach-from-a-container-without-stopping-it/45985809#45985809

评论

评论加载中……