Docker学习笔记

大彬
大约 13 分钟

简介

Docker是一个开源的应用容器引擎,通过容器可以隔离应用程序的运行时环境(程序运行时依赖的各种库和配置),比虚拟机更轻量(虚拟机在操作系统层面进行隔离)。docker的另一个优点就是build once, run everywhere,只编译一次,就可以在各个平台(windows、linux等)运行。

基本概念

docker的基本概念:

  1. 镜像(image),类似于虚拟机中的镜像,可以理解为可执行程序。

  2. 容器(container),类似于一个轻量级的沙盒,可以将其看作一个极简的Linux系统环境。Docker引擎利用容器来运行、隔离各个应用。容器是镜像创建的应用实例,可以创建、启动、停止、删除容器,各个容器之间是是相互隔离的,互不影响。

  3. 镜像仓库(repository),是Docker用来集中存放镜像文件的地方。注意与注册服务器(Registry)的区别:注册服务器是存放仓库的地方,一般会有多个仓库;而仓库是存放镜像的地方,一般每个仓库存放一类镜像,每个镜像利用tag进行区分,比如Ubuntu仓库存放有多个版本(12.04、14.04等)的Ubuntu镜像。

  4. 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上。

  1. 登录docker hub:docker login
  2. 将本地镜像推送到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

部署多个服务

  1. 使用docker-compose.yml定义需要部署的服务;
  2. 使用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

参考内容

只要一小时,零基础入门Dockeropen in new window

Loading...