Docker学习笔记
简介
Docker是一个开源的应用容器引擎,通过容器可以隔离应用程序的运行时环境(程序运行时依赖的各种库和配置),比虚拟机更轻量(虚拟机在操作系统层面进行隔离)。docker的另一个优点就是build once, run everywhere,只编译一次,就可以在各个平台(windows、linux等)运行。
基本概念
docker的基本概念:
镜像(image),类似于虚拟机中的镜像,可以理解为可执行程序。
容器(container),类似于一个轻量级的沙盒,可以将其看作一个极简的Linux系统环境。Docker引擎利用容器来运行、隔离各个应用。容器是镜像创建的应用实例,可以创建、启动、停止、删除容器,各个容器之间是是相互隔离的,互不影响。
镜像仓库(repository),是Docker用来集中存放镜像文件的地方。注意与注册服务器(Registry)的区别:注册服务器是存放仓库的地方,一般会有多个仓库;而仓库是存放镜像的地方,一般每个仓库存放一类镜像,每个镜像利用tag进行区分,比如Ubuntu仓库存放有多个版本(12.04、14.04等)的Ubuntu镜像。
dockerfile,image的编译配置文件,docker就是"编译器"。
docker的基本命令:
1、docker build:我们只需要在dockerfile中指定需要哪些程序、依赖什么样的配置,之后把dockerfile交给“编译器”docker进行“编译”,生成的可执行程序就是image。
2、docker run:运行image,运行起来后就是docker container。
3、docker pull:到Docker Hub(docker registry)下载别人写好的image。
图片来源:知乎小灰
docker镜像常用命令
添加docker仓库位置
安装yum-utils:
yum install -y yum-utils device-mapper-persistent-data lvm2
添加仓库地址:
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
安装docker服务
yum install docker-ce
启动 docker 服务
systemctl start docker
重启docker服务
systemctl restart docker.service
搜索镜像
docker search java
下载镜像:
不加版本号,则默认下载最新版本。
docker pull nginx:1.18.0
列出镜像
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx 1.18.0 c2c45d506085 7 days ago 133MB
nginx 1.17.0 719cd2e3ed04 22 months ago 109MB
java 8 d23bdf5b1b1b 4 years ago 643MB
删除镜像
删除镜像前必须先删除以此镜像为基础的容器。
docker rmi -f imageID # -f 强制删除镜像
删除所有没有引用的镜像(找出IMAGE ID为none的镜像):
docker rmi `docker images | grep none | awk '{print $3}'`
强制删除所有镜像:
docker rmi -f $(docker images)
打包镜像
# -t 表示指定镜像仓库名称/镜像名称:镜像标签 .表示使用当前目录下的Dockerfile文件
docker build -t mall/mall-admin:1.0-SNAPSHOT .
创建镜像
镜像的创建也有两种:
- 利用已有的镜像创建容器之后进行修改,之后commit生成镜像
- 利用Dockerfile创建镜像
(1)利用已有的镜像创建容器之后进行修改
利用镜像启动容器:
[root@xxx ~]# docker run -it java:8 /bin/bash # 启动一个容器
[root@72f1a8a0e394 /]# # 这里命令行形式变了,表示已经进入了一个新环境
[root@72f1a8a0e394 /]# vim # 此时的容器中没有vim
bash: vim: command not found
[root@72f1a8a0e394 /]# apt-get update # 更新软件包
[root@72f1a8a0e394 /]# apt-get install vim # 安装vim
exit退出该容器,然后查看docker中运行的程序(容器):
[root@VM_0_7_centos ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
857aa43eeed4 java:8 "/bin/bash" 19 minutes ago Exited (127) 4 seconds ago gifted_blackburn
将容器转化为一个镜像,此时Docker引擎中就有了我们新建的镜像,此镜像和原有的java镜像区别在于多了个vim工具。
[root@VM_0_7_centos ~]# docker commit -m "java with vim" -a "tyson" 857aa43eeed4 tyson/java:vim
sha256:67c4b3658485690c9128e0b6d4c5dfa63ec100c89b417e3148f3c808254d6b9b
[root@VM_0_7_centos ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tyson/java vim 67c4b3658485 7 seconds ago 684MB
运行新建的镜像:
[root@VM_0_7_centos ~]# docker run -it tyson/java:vim /bin/bash
root@88fead8e7db5:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@88fead8e7db5:/# touch demo.txt
root@88fead8e7db5:/# vim demo.txt
(2)利用Dockerfile创建镜像
dockerfile用于告诉docker build执行哪些操作。
#该镜像以哪个镜像为基础
FROM java:8
#构建者的信息
MAINTAINER tyson
#build镜像执行的操作
RUN apt-get update
RUN apt-get install vim
#拷贝本地文件到镜像中
COPY ./* /usr/tyson/
利用build命令构建镜像:
docker build -t="tyson/java:vim" .
其中-t用来指定新镜像的用户信息、tag等。最后的点表示在当前目录寻找Dockerfile。
构建完成之后,通过docker images
可以查看生成的镜像。
推送镜像:
# 登录Docker Hub
docker login
# 给本地镜像打标签为远程仓库名称
docker tag mall/mall-admin:1.0-SNAPSHOT macrodocker/mall-admin:1.0-SNAPSHOT
# 推送到远程仓库
docker push macrodocker/mall-admin:1.0-SNAPSHOT
docker hub
Docker官方维护了一个DockerHub的公共仓库,里边包含有很多平时用的较多的镜像。除了从上边下载镜像之外,我们也可以将自己自定义的镜像发布(push)到DockerHub上。
- 登录docker hub:
docker login
- 将本地镜像推送到docker hub,镜像的username需要与docker hub的username一致:
docker push tyson14/java:vim
修改镜像存放位置
1、查看镜像存放位置:
docker info | grep "Docker Root Dir"
Docker Root Dir: /var/lib/docker
2、关闭docker服务:
systemctl stop docker
3、原镜像目录移动到目标目录:
mv /var/lib/docker /home/data/docker
4、建立软连接:
ln -s /home/data/docker /var/lib/docker
5、再次查看镜像存放位置,发现已经修改。
docker容器常用命令
新建容器
新建并启动容器(docker容器运行必须有一个前台进程, 如果没有前台进程执行,容器认为空闲,就会自行退出。所以需要先创建一个前台进程):
docker run -it --name java java:8 /bin/bash
docker run -p 33055:33055 --name nginx \
> -v /home/data:/home/data \
> nginx:1.18.0 \
> -e TZ="Asia/Shanghai"
# -d nginx:1.18.0 -d表示容器以后台方式运行
- -p:将宿主机和容器端口进行映射,格式为:宿主机端口:容器端口;
- --name:指定容器名称,之后可以通过容器名称来操作容器;
- -e:设置容器的环境变量,这里设置的是时区;
- -v:将宿主机上的文件挂载到容器上,格式为:宿主机文件目录:容器文件目录;
- -d:表示容器以后台方式运行。终端不会输出任何运行信息;
- -i: 以交互模式运行容器,通常与 -t 同时使用;
- -t: 为容器分配一个终端,通常与 -i 同时使用。
使用-it,此时如果使用exit退出,则容器的状态处于Exit,而不是后台运行。如果想让容器一直运行,而不是停止,可以使用快捷键 ctrl+p ctrl+q 退出,此时容器的状态为Up。
创建MySQL容器:
docker run --name mysql4blog -e MYSQL_ROOT_PASSWORD=123456 -p 3307:3307 -d mysql:8.0.20
-name
: 给新创建的容器命名,此处命名为mysql4blog
-e
: 配置信息,此处配置MySQL的 root 用户的登录密码-p
: 端口映射,此处映射主机的3307端口到容器的3307端口- -d: 成功启动同期后输出容器的完整ID
- 最后一个
mysql:8.0.20
指的是mysql
镜像
查看容器
列出运行中的容器,-a
参数可以列出所有容器:
docker ps
停止容器
使用容器名称或者容器ID:
docker stop $ContainerName(or $ContainerId)
强制停止容器:
docker kill $ContainerName
启动容器
docker start $ContainerName
重启容器
docker restart nginx
进入容器
进入名字为mysql的容器,同时打开命令行终端。使用exit时,容器不会停止。
docker exec -it mysql /bin/bash
docker attach可以将本机的输入直接输到容器中,容器的输出会直接显示在本机的屏幕上。如果使用exit或者ctrl+c退出,会导致容器的停止。
docker attach container_name/container_id
新建并运行容器时,使用docker run -it tyson/java:vim /bin/bash
,直接进入容器命令行界面。
使用exit退出命令行之后,重新进入容器:
1、先查询容器id:docker inspect --format "{{.State.Pid}}" nginx
2、根据查到的容器id进入容器:nsenter --target 28487 --mount --uts --ipc --net --pid
[root@VM_0_7_centos ~]# docker inspect --format "{{.State.Pid}}" nginx
28487
[root@VM_0_7_centos ~]# nsenter --target 28487 --mount --uts --ipc --net --pid
mesg: ttyname failed: No such device
root@b217a35fc808:/# ls -l
删除容器
根据ContainerName删除容器:
docker rm nginx
按名称通配符删除容器,比如删除以名称mall-
开头的容器:
docker rm `docker ps -a | grep mall-* | awk '{print $1}'`
强制删除所有容器:
docker rm -f $(docker ps -a -q)
容器日志
根据ContainerName查看容器产生的日志:
docker logs nginx
动态查看容器产生的日志:
docker logs -f nginx
实时查看日志最后200行:
docker logs -f --tail 200 mysql
容器ip
docker inspect --format '{{.NetworkSettings.IPAddress}}' nginx
容器启动方式
# 将容器启动方式改为always
docker container update --restart=always $ContainerName
资源占用
查看指定容器资源占用状况,比如cpu、内存、网络、io状态:
docker stats nginx
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
b217a35fc808 nginx 0.00% 3.641MiB / 1.795GiB 0.20% 656B / 0B 11.3MB / 8.19kB 2
查看所有容器资源占用情况:
docker stats -a
磁盘使用情况
docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 3 1 885.4MB 752.5MB (84%)
Containers 1 1 1.258kB 0B (0%)
Local Volumes 0 0 0B 0B
Build Cache 0 0 0B 0B
执行容器内部命令
[root@VM_0_7_centos ~]# docker exec -it nginx /bin/bash
root@b217a35fc808:/# ll
bash: ll: command not found
root@b217a35fc808:/# ls -l
total 80
drwxr-xr-x 2 root root 4096 Apr 8 00:00 bin
drwxr-xr-x 2 root root 4096 Mar 19 23:44 boot
指定账号进入容器内部:
docker exec -it --user root nginx /bin/bash
网络
查看网络:
docker network ls
NETWORK ID NAME DRIVER SCOPE
5f0d326b7082 bridge bridge local
af84aa332f22 host host local
741c1734f3bb none null local
创建外部网络:
docker network create -d bridge my-bridge-network
创建容器时指定网络:
docker run -p 33056:33056 --name java \
> --network my-bridge-network \
> java:8
复制文件
将当前目录tpch文件夹复制到mysql容器相应的位置:
docker cp tpch mysql56:/var/lib/mysql #mysql56为容器名
容器文件拷贝到宿主机:
docker cp 容器名:要拷贝的文件在容器里面的路径 要拷贝到宿主机的相应路径
docker-compose
Docker Compose是一个用于定义和运行多个docker容器应用的工具。使用YAML文件配置多个应用服务,通过这个YAML文件一次性部署配置的所有服务。
安装
curl -L https://get.daocloud.io/docker/compose/releases/download/1.24.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
修改文件的权限为可执行:
chmod +x /usr/local/bin/docker-compose
查看是否安装成功:
docker-compose --version
常用命令
创建、启动容器(默认配置文件docker-compose.yml):
# -d表示在后台运行
docker-compose up -d
指定文件启动:
docker-compose -f docker-compose.yml up -d
停止所有相关容器:
docker-compose stop
列出所有容器信息:
docker-compose ps
部署多个服务
- 使用docker-compose.yml定义需要部署的服务;
- 使用docker-compose up命令一次性部署配置的所有服务。
定义配置文件
ports:指定主机和容器的端口映射(HOST:CONTAINER)
volumes:将主机目录挂载到容器(HOST:CONTAINER)
link:连接其他容器(同一个网络下)的服务(SERVICE:ALIAS)
services:
elasticsearch:
image: elasticsearch:7.6.2
container_name: elasticsearch
user: root
environment:
- "cluster.name=elasticsearch" #设置集群名称为elasticsearch
- "discovery.type=single-node" #以单一节点模式启动
- "ES_JAVA_OPTS=-Xms128m -Xmx128m" #设置使用jvm内存大小
volumes:
- /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins #插件文件挂载
- /mydata/elasticsearch/data:/usr/share/elasticsearch/data #数据文件挂载
ports:
- 9200:9200
- 9300:9300
logstash:
image: logstash:7.6.2
container_name: logstash
environment:
- TZ=Asia/Shanghai
volumes:
- /mydata/logstash/logstash.conf:/usr/share/logstash/pipeline/logstash.conf #挂载logstash的配置文件
depends_on:
- elasticsearch #kibana在elasticsearch启动之后再启动
link:
- elasticsearch:es #可以用es这个域名访问elasticsearch服务
启动服务
先将docker-compose.yml上传至Linux服务器,再在当前目录下运行如下命令(默认配置文件docker-compose.yml):
docker-compose up -d
maven插件构建docker镜像
docker镜像仓库
服务器创建docker镜像仓库docker registry:
docker run -d -p 5000:5000 --restart=always --name registry2 registry:2
docker开启远程访问
docker开启远程访问的端口2375,修改docker.service文件:
vi /usr/lib/systemd/system/docker.service
修改内容如下:
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock
unix:///var/run/docker.sock
:unix socket,本地客户端将通过这个来连接 Docker Daemon。 tcp://0.0.0.0:2375
:tcp socket,表示允许任何远程客户端通过 2375 端口连接 Docker Daemon。
docker支持http上传镜像
echo '{ "insecure-registries":["192.168.3.101:5000"] }' > /etc/docker/daemon.json
重启docker
使配置生效:
systemctl daemon-reload
重启docker服务:
systemctl restart docker
开放端口
firewall-cmd --zone=public --add-port=2375/tcp --permanent
firewall-cmd --reload
构建docker镜像
在应用的pom.xml文件中添加docker-maven-plugin的依赖:
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.1.0</version>
<executions>
<execution>
<id>build-image</id>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
<configuration>
<imageName>mall-tiny/${project.artifactId}:${project.version}</imageName>
<dockerHost>http://tysonbin.com:2375</dockerHost>
<baseImage>java:8</baseImage>
<entryPoint>["java", "-jar","/${project.build.finalName}.jar"]
</entryPoint>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>${project.build.finalName}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
相关配置说明:
- executions.execution.phase:此处配置了在maven打包应用时构建docker镜像;
- imageName:用于指定镜像名称,mall-tiny是仓库名称,
${project.artifactId}
为镜像名称,${project.version}
为版本号; - dockerHost:打包后上传到的docker服务器地址;
- baseImage:该应用所依赖的基础镜像,此处为java;
- entryPoint:docker容器启动时执行的命令;
- resources.resource.targetPath:将打包后的资源文件复制到该目录;
- resources.resource.directory:需要复制的文件所在目录,maven打包的应用jar包保存在target目录下面;
- resources.resource.include:需要复制的文件,打包好的应用jar包。
修改application.yml中的域名,将localhost改为db。可以把docker中的容器看作独立的虚拟机,mall-tiny-docker访问localhost自然会访问不到mysql,docker容器之间可以通过指定好的服务名称db进行访问,至于db这个名称可以在运行mall-tiny-docker容器的时候指定。
spring:
datasource:
url: jdbc:mysql://db:3306/mall?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: root
执行maven的package命令,执行成功之后,镜像仓库会生成mall-tiny-docker镜像。
启动mysql服务:
docker run -p 3306:3306 --name mysql \
-v /mydata/mysql/log:/var/log/mysql \
-v /mydata/mysql/data:/var/lib/mysql \
-v /mydata/mysql/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
进入运行mysql的docker容器:docker exec -it mysql /bin/bash
启动mall-tiny-docker服务,通过--link表示在同一个网络内(可以在启动容器时通过--network指定),应用可以用db这个域名访问mysql服务:
docker run -p 8080:8080 --name mall-tiny-docker \
--link mysql:db \ # 在同一个网络内不同容器之间可以通过--link指定的服务别名互相访问,containName:alias
-v /etc/localtime:/etc/localtime \
-v /mydata/app/mall-tiny-docker/logs:/var/logs \
-d mall-tiny/mall-tiny-docker:0.0.1-SNAPSHOT
其他
给nginx增加端口映射
nginx一开始只映射了80端口,后面载部署项目的时候,需要用到其他端口,不想重新部署容器,所以通过修改配置文件的方式给容器添加其他端口。
1、执行命令docker inspect nginx
,找到容器id
2、停止容器docker stop nginx
,不然修改了配置会自动还原
3、修改hostconfig.json
cd /var/lib/docker/containers/135254e3429d1e75aa68569137c753b789416256f2ced52b4c5a85ec3849db87 # container id
vim hostconfig.json
添加端口:
"PortBindings": {
"80/tcp": [
{
"HostIp": "",
"HostPort": "80"
}
],
"8080/tcp": [
{
"HostIp": "",
"HostPort": "8080"
}
]
},
4、修改同目录下 config.v2.json
"ExposedPorts": {
"80/tcp": {},
"8080/tcp": {},
"8189/tcp": {}
},
5、重启容器
systemctl restart docker.service # 重启docker服务
docker start nginx