docker容器本质是多个容器卷的叠加,启动后的容器卷处于容器卷最顶层,不做特殊配置和处理的话,不同的容器之间是相互隔离的,包括文件存储和网络的隔离,其中文件存储可以通过挂载volumes来实现文件同步。
每个容器创建时,会默认创建一对虚拟网卡,用于来链接容器和宿主机,也就是veth-pair。
我们现在创建一个容器,然后分别查看宿主机和容器的ip地址。
#容器内部
[root@74caeaf4fddc /]# ip addr
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
259: eth0@if260: mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:12:00:06 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.18.0.6/16 brd 172.18.255.255 scope global eth0
valid_lft forever preferred_lft forever
如上, 容器内部查看ip,有一个259的网卡,后面的eth0@if260是指的链接宿主机260虚拟网卡,通过创建一对虚拟网卡,来链接宿主机
#宿主机
[root@VM-0-3-centos ~]# ip addr
....
3: docker0: mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ca:eb:ae:cd brd ff:ff:ff:ff:ff:ff
inet 172.18.0.1/16 brd 172.18.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:caff:feeb:aecd/64 scope link
valid_lft forever preferred_lft forever
260: vethd02d55c@if259: mtu 1500 qdisc noqueue master docker0 state UP g roup default
link/ether ca:ff:68:26:34:e4 brd ff:ff:ff:ff:ff:ff link-netnsid 4
inet6 fe80::c8ff:68ff:fe26:34e4/64 scope link
valid_lft forever preferred_lft forever
....
我们直接创建容器相当于在容器后面默认加上网络配置参数,默认加入docker0网关,可以看到docker0网关是172.18.0.1,新创建的容器ip是172.18.0.6,两者是同一个ip段,网络互通。
docker run -d --net bridge centos
所以容器间的互通,可以直接通过ip访问,但是在我们实际使用过程中,容器启动顺序不一样,会导致ip有变化,所以我们可以自己建一个bridge网络桥,命名mynet,然后手动让新建的容器都加入这个网络桥 --net mynet,容器之间就可以通过容器名相互ping通。
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
让所有容器加入自定义的网络bridge,然后我们的服务配置就可以直接使用容器名来映射ip,例如mysql host直接使用db, redis host使用redis来代替。
spring:
datasource:
url: jdbc:mysql://db:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: test
password: 123456
redis:
host: redis # Redis服务器地址
database: 0 # Redis数据库索引(默认为0)
port: 6379 # Redis服务器连接端口
password: #不设置密码
但是到了docker-compose里面,这个创建网络的动作会被再次简化,如果没有特殊声明每个服务所在的网络,那么在yaml服务启动时,会默认创建一个bridge,并且将同一个yml中所有服务都被链接至该bridge。同一个yaml文件中服务可以相互通过服务名ping通。
#docker-compose启动项目,默认创建一个app_default的network
[root@VM-0-3-centos app]# docker-compose -f docker-compose-env.yml up --build
Creating network "app_default" with the default driver
Creating redis_isr ... done
Creating db123 ... done
Attaching to redis_isr, db123
....
但是我们实际生产中,很多时候是多个docker-compose.yml文件分开启动,所以需要通过external-links来链接外部服务,前提是外部服务已经加入一个bridge网络,而external–links本质还是表示将当前yml文件的网络链接到外部服务的bridge网络中,值得一提的是,如果是docker默认的网络,是无法进行external–links。
#先在上方进行redis和mysql的启动,并创建app_default网络,然后再启动2个服务,其中使用external--links到redis和db123;
#会发现后面启动的2个服务并未创建网络桥
[root@VM-0-3-centos app]# docker-compose -f docker-compose-app.yml up --build
Successfully built 06fba95fdb2c
Successfully tagged isr/isr-user-test:1.0
Building isr-discoveryserver
....
我们再查看容器网络app_default,其中有4个容器,正是我们刚刚启动的4个服务。完美链接。
"Name": "app_default",
"Id": "7e02c370f248ad744859c94bc6f0b9c550ec492e74937a792636f60e8bd71e8b",
"Created": "2021-09-12T21:51:24.373375115+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.29.0.0/16",
"Gateway": "172.29.0.1"
}
]
},
"Internal": false,
"Attachable": true,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"2851dede459e270088ad95d858499b2477bc53f0ecf31e0c36f72a27f6b6e6b9": {
"Name": "db123",
"EndpointID": "9762e796ceaf702613273fcf935524e4bb6e9ebed79d0d549036552316913626",
"MacAddress": "02:42:ac:1d:00:02",
"IPv4Address": "172.29.0.2/16",
"IPv6Address": ""
},
"54f8d63cc8eeb5d97c6b0e3ac2f257116c99157bb3613850f9bb37c5dbea5117": {
"Name": "isr-user-test",
"EndpointID": "16e7794b770a7fab2293332177f6fd754062851a1478bac2cb96ab2e6f4d5069",
"MacAddress": "02:42:ac:1d:00:05",
"IPv4Address": "172.29.0.5/16",
"IPv6Address": ""
},
"7121b20ace1bb31833e753e2a4154e198eb062b038e245bbb647a8b2594ef93d": {
"Name": "redis_isr",
"EndpointID": "a29027628abe1a694e922bab38d95cc1f03709828302445a0e8dee24e771e780",
"MacAddress": "02:42:ac:1d:00:03",
"IPv4Address": "172.29.0.3/16",
"IPv6Address": ""
},
"bb1b901b9cd2e5e074e0c548134a04311eadd67373da7cb2f4761a8040d74c7f": {
"Name": "isr-discoveryserver-test",
"EndpointID": "3115410d322ed1bc8745d5b2725ab21ab2172bb2be2ac922c12ea71098c5b309",
"MacAddress": "02:42:ac:1d:00:04",
"IPv4Address": "172.29.0.4/16",
"IPv6Address": ""
}
},
镜像操作
docker pull mysql:5.0 #拉取指定版本镜像,版本不写默认最新版
docker images #查询镜像,-a 包含中间层镜像,-q只查看id
docker rmi -f mysql #移除镜像 -f 表示强制
docker rmi -f $(docker images -aq) #移除所有镜像
容器基本操作
docker run -it(-d) -p(-P) 3307:3306 --name db -v /usr/app/data:/var/lib/data mysql
#run从镜像创建容器,如果不存在则自动拉取
#-it 以交互形式打开容器,并分配一个终端,-d 以守护方式后台运行容器
#-p 将容器内部的3306端口映射到外部服务器的3307端口,-P 将3306映射到外部随机端口
#--name 给容器命名
#-v 容器卷挂载,将容器中的/var/lib/data路径挂载到服务器的/usr/app/data路径,无论哪个文件夹对其中文件进行操作,都会同步到另一个文件夹中
docker exec -it mysql /bin/bash(sh) #以交互新终端进入容器
docker rm -f mysql #删除容器
docker rm -f $(docker ps -aq) #删除全部容器
docker start/stop mysql
容器信息查看
docker inspect redis
#查看容器相信信息,包括mount挂载状态,networks网络状态,
docker top redis #查看容器状态
for i in `docker ps |grep Up|awk '{print $1}'`;do echo \ &&docker top $i; done #查看所有运行容器的进程
dockers logs mysql #查看启动日志
使用dockerfile生成镜像,关键字全部大写。
FROM 基于哪个镜像继续叠加镜像层
ADD 将当前路径中文件复制到容器中,要注意文件路径
RUN 运行容器中命令
EXPOSE 将端口暴露给其他容器,但是外部无法访问
FROM java:8
ADD isr-user-1.0-SNAPSHOT.jar /isr-user-docker.jar
RUN bash -c 'touch /isr-user-docker.jar'
EXPOSE 10119
ENTRYPOINT ["java", "-jar","-Xms512m", "-Xmx512m", "-Xmn256m", "/isr-user-docker.jar", "--spring.profiles.active=test"]
MAINTAINER wuhong
-t tag, 尾端的.表示dockerfile文件,文件名默认Dockerfile
docker build -t 自定义镜像名:[tag] .
external_links链接外部服务,在当前服务中,可以直接使用该外部服务名表示host
ports,expose:ports是将容器内的端口映射到宿主机端口,由宿主机端口对外提供容器端口服务,expose只是将暴露容器的端口给到其他容器,但是并没有暴露给外部访问
docker-compose -p test -f dockers-compose.yml up --build
#-p表示项目名,默认当前文件夹名,如果当前文件夹有多个yml文件,建议指定项目名
#-f表示yml文件
version: '3.3' #版本号和docker engine版本对应
services:
isr-user: #服务名
build: ./isr-user #指定dockerfile路径
image: isr/isr-user-test:1.0 #
container_name: isr-user-test
ports:
- 10119:10119
volumes:
- /mydata/app/isr-user/logs:/mnt/isr/log
- /etc/localtime:/etc/localtime
environment:
- 'TZ="Asia/Shanghai"'
external_links:
- db
- redis
isr-discoveryserver:
build: ./isr-discoveryserver
image: isr/isr-discoveryserver-test:1.0
container_name: isr-discoveryserver-test
ports:
- 9000:9000
volumes:
- /mydata/app/isr-user/logs:/mnt/isr/log
- /etc/localtime:/etc/localtime
environment:
- 'TZ="Asia/Shanghai"'
version: '3.3'
services:
mysql:
image: mysql:8.0
container_name: mysql_test
restart: always
environment:
MYSQL_ROOT_PASSWORD: root #设置root帐号密码
ports:
- 3306:3306
volumes:
- /mydata/mysql/data/db:/var/lib/mysql #数据文件挂载
- /mydata/mysql/data/conf:/etc/mysql/conf.d #配置文件挂载
- /mydata/mysql/log:/var/log/mysql #日志文件挂载
redis:
image: redis:5.0
container_name: redis_test
restart: unless-stopped
ports:
- 6379:6379
volumes:
- /mydata/redis/data:/data #数据文件挂载
- /mydata/redis/conf:/etc/redis/redis.conf #配置文件挂载