Docker学习

  • Post author:
  • Post category:其他




查看未运行的的container

docker ps -f "status=exited"
或
docker container ls -f "status=exited"



docker commit命令

docker commit: 从容器创建一个新的镜像。

OPTIONS说明:

  • a: 提交的镜像作者;

  • c: 使用Dockerfile指令来创建镜像;

  • m: 提交时的说明文字;

  • p: 在commit时,将容器暂停。

docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]



Dockerfile


#

Dockerfile注释



FROM 文件的开始
  • FROM scratch # 从头开始制作一个最简单的镜像基础
  • FROM centos # 使用centos作为系统,没有则自动拉取
  • FROM centos:7.0 # 指定系统版本


LABEL 注释
  • LABEL version=“1.0”
  • LABEL author=“sxj”


RUN 执行命令,每执行一次,镜像就多一层
  • RUN yum -y update
  • RUN yum install xxx

由于每次RUN都会多一层,建议将上面结合起来写:

RUN yum -y update && yum -y install xxx


WORKDIR 进入或创建目录
  • WORKDIR /root # 进入/root目录
  • WORKDIR /haha # 创建/haha目录


ADD and COPY 将本地文件加入image
  • ADD可以解压缩文件
  • ADD hello / # 添加hello到根目录
  • ADD xxx.tar.gz / # 添加并解压到跟目录
  • COPY hello / # 添加hello到根目录


ENV 定义镜像的环境变量
  • ENV MYSQL_VERSION 5.6 # 设置常量
  • RUN apt-get -y install mysql-server=”${MYSQL_VERSION}” # 安装5.6版本mysql



分享docker image到docker hub

https://hub.docker.com/

注:image名字一定要以自己docker hub的用户名开头

// 登录
docker login

// 推送镜像
docker image push scoola/diff

// 拉取镜像
docker pull scoola/diff



分享Dockerfile

分享docker image不如分享Dockerfile,更加安全。



docker 更换源

https://www.cnblogs.com/zpchcbd/p/11696697.html

$ cd /etc/docker
$ cat daemon.json 
{
"registry-mirrors": [
"https://kfwkfulq.mirror.aliyuncs.com",
"https://2lqq34jg.mirror.aliyuncs.com",
"https://pee6w651.mirror.aliyuncs.com",
"https://registry.docker-cn.com",
"http://hub-mirror.c.163.com"
],
"dns": ["8.8.8.8","8.8.4.4"]
}

然后重启docker

systemctl docker restart



docker tag

标记本地镜像,将其归入某一仓库。

将镜像ubuntu:15.10标记为 runoob/ubuntu:v3 镜像:

root@runoob:~# docker tag ubuntu:15.10 runoob/ubuntu:v3
root@runoob:~# docker images   runoob/ubuntu:v3
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
runoob/ubuntu       v3                  4e3b13c8a266        3 months ago        136.3 MB



搭建私有docker registry仓库

https://hub.docker.com/_/registry

查看私有仓库日志:

浏览器访问:

http://127.0.0.1:5000/v2/_catalog

也可搭建

Harbor

,具有web管理界面, 可参考

Harbor介绍文档


Harbor和Registry的比较

Harbor和Registry都是Docker的镜像仓库,但是Harbor作为更多企业的选择,是因为相比较于Regisrty来说,它具有很多的优势。


1.提供分层传输机制,优化网络传输

Docker镜像是是分层的,而如果每次传输都使用全量文件(所以用FTP的方式并不适合),显然不经济。必须提供识别分层传输的机制,以层的UUID为标识,确定传输的对象。


2.提供WEB界面,优化用户体验

只用镜像的名字来进行上传下载显然很不方便,需要有一个用户界面可以支持登陆、搜索功能,包括区分公有、私有镜像。


3.支持水平扩展集群

当有用户对镜像的上传下载操作集中在某服务器,需要对相应的访问压力作分解。


4.良好的安全机制

企业中的开发团队有很多不同的职位,对于不同的职位人员,分配不同的权限,具有更好的安全性。


5.Harbor提供了基于角色的访问控制机制,并通过项目来对镜像进行组织和访问权限的控制。

kubernetes中通过namespace来对资源进行隔离,在企业级应用场景中,通过将两者进行结合可以有效将kubernetes使用的镜像资源进行管理和访问控制,增强镜像使用的安全性。尤其是在多租户场景下,可以通过租户、namespace和项目相结合的方式来实现对多租户镜像资源的管理和访问控制。


同时docker registry的一些缺陷:

  • 缺少认证机制,任何人都可以随意拉取及上传镜像,安全性缺失
  • 缺乏镜像清理机制,镜像可以push却不能删除,日积月累,占用空间会越来越大
  • 缺乏相应的扩展机制



docker容器限制

# 限制内存
docker run --memory=100M ubuntu

# 设置占有cpu相对权重
docker run --cpu-shares=1 ubuntu



docker进入容器


docker attach

docker attach可以attach到一个已经运行的容器的stdin,然后进行命令执行的动作。

但是需要注意的是,如果从这个stdin中exit,会导致容器的停止。


docker exec

在docker 里面新开了一个bash 进程,在该终端可以通过命令和容器交互,类似于通过ssh和远程linux server 交互。

docker exec -it 0e63f8c3d293 /bin/sh

使用-it时,则和我们平常操作console界面类似。而且也不会像attach方式因为退出,导致整个容器退出。



结束所有镜像

docker stop $(docer ps -aq)

# 其中docker ps -aq 列出所有容器ID(CONTAINER ID)



docker inspect

获取容器/镜像的元数据。

docker inspect [OPTIONS] NAME|ID [NAME|ID…]

OPTIONS说明:

  • -f :指定返回值的模板文件。
  • -s :显示总的文件大小。
  • –type :为指定类型返回JSON。



docker network

  • docker network inspect

    在一个或多个网络上显示详细信息

# 桥接信息
docker network inspect bridge
  • docker network connect

    将容器连接到网络

  • docker network create

    创建一个网络

  • docker network disconnect

    从网络断开容器

  • docker network inspect

    显示一个或多个网络的详细信息

  • docker network ls

    列出网络

  • docker network prune

    删除所有未使用的网络

  • docker network rm

    删除一个或多个网络



docker run –link

可以用来链接2个容器,使得源容器(被链接的容器)和接收容器(主动去链接的容器)之间可以互相通信,并且接收容器可以获取源容器的一些数据,如源容器的环境变量。

举例:

# 环境: 已启动一个名为redis的container提供缓存服务。
[root@centos7 compose]# docker ps
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS                      NAMES
3781aa66ff19        redis                           "docker-entrypoint..."   12 minutes ago      Up 12 minutes       0.0.0.0:6379->6379/tcp     redis



# 将新新启动的名为 web_incr 的container链接到 redis container
# 并通过-e命令设置环境变量RDIS_HOST=redis container
# -d 容器后台运行
# -p 端口映射
docker run -d --link redis -p 6000:9999 --name web_incr -e REDIS_HOST=redis web_incr

# 这样启动链接后,就可以在代码中直接通过获取环境变量来链接redis,而不需要写死redis服务地址

尝试访问,可发现num有增加:
[root@centos7 compose]# curl http://127.0.0.1:6000/
Hello! Incr num is 25, hostname:a73f0e217f6f
[root@centos7 compose]# curl http://127.0.0.1:6000/
Hello! Incr num is 26, hostname:a73f0e217f6f
[root@centos7 compose]# docker ps
CONTAINER ID        IMAGE                           COMMAND                  CREATED              STATUS              PORTS                      NAMES
a73f0e217f6f        web_incr                        "/bin/sh -c 'pytho..."   About a minute ago   Up About a minute   0.0.0.0:6000->9999/tcp     web_incr

且可以发现,返回的hostname即为web_incr的CONTAINER ID

web_incr代码如下:

from flask import Flask
from redis import Redis
import socket
import os

app = Flask(__name__)

redis = Redis(host=os.environ.get('REDIS_HOST', '127.0.0.1'), port=6379)

@app.route('/')
def hello():
    redis.incr('hits')
    return 'Hello! Incr num is {}, hostname:{}'.format(int(redis.get('hits')),
            socket.gethostname())

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=9999, debug=True)

web_incr Dockerfile:

FROM python

ENV APP_ROOT=/src/code
WORKDIR ${APP_ROOT}/

COPY . ${APP_ROOT}/

RUN pip install Flask -i https://pypi.tuna.tsinghua.edu.cn/simple
RUN pip install redis -i https://pypi.tuna.tsinghua.edu.cn/simple

CMD python main.py



Docker Compose

经过上述通过–link,我们的web_incr容器可以访问redis容器,但部署很麻烦,如果仅仅2个容器尚可接受,若需要部署的容器更多,那就需要Docker compose来帮我们实现了。

安装Docker Compose:

1.下载
curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
2.增加执行权限  
chmod +x /usr/local/bin/docker-compose

创建docker-compose.yaml

[root@centos7 compose]# ls
docker-compose.yml  Dockerfile  main.py
[root@centos7 compose]# cat docker-compose.yml 
# yaml 配置实例
version: '3'
services:
  web:
    build: .
    ports:
        - "6000:9999"
    links:
        - redis
    environment:
        REDIS_HOST: redis
  redis:
    image: redis

通过docker-compose启动redis和web_incr容器:

# 注:该命令必须在docker-compose.yml路径下运行
[root@centos7 compose]# docker-compose up -d
Creating network "compose_default" with the default driver
Building web
Step 1/7 : FROM python
 ---> 28a4c88cdbbf
Step 2/7 : ENV APP_ROOT /src/code
 ---> Using cache
 
...省略镜像构建

Creating compose_redis_1 ... done
Creating compose_web_1   ... done

# 可发现2个容器都已运行,且可以发现多了一个名为compose_web的镜像
[root@centos7 compose]# docker images
REPOSITORY                         TAG                 IMAGE ID            CREATED             SIZE
compose_web                        latest              333f57c75b05        3 minutes ago       892 MB
web_incr                           latest              77ad408fd8a3        20 minutes ago      892 MB

# 查看容器,可以看到新启动了名为compose_web和redis的容器:
[root@centos7 compose]# docker ps
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS                      NAMES
b461e70356e2        compose_web                     "/bin/sh -c 'pytho..."   5 minutes ago       Up 5 minutes        0.0.0.0:6000->9999/tcp     compose_web_1
e342d72d2109        redis                           "docker-entrypoint..."   5 minutes ago       Up 5 minutes        6379/tcp                   compose_redis_1

# 请求查看,可正常运行,且hostname与compose_web的CONTAINER ID 相同。
[root@centos7 compose]# curl http://127.0.0.1:6000/
Hello! Incr num is 1, hostname:b461e70356e2
[root@centos7 compose]# curl http://127.0.0.1:6000/
Hello! Incr num is 2, hostname:b461e70356e2

至此,我们已经通过docker-compose实现了快速部署redis和web_incr的服务。

但是,实际使用中,若我们想动态扩容web_incr方法还是很麻烦。为了解决这个问题,我们可以引入负载均衡,随后就可以借助docker-compose实现动态扩容。

首先我们将之前启动的容器停止:

[root@centos7 compose]# docker-compose stop
Stopping compose_web_1   ... done
Stopping compose_redis_1 ... done

修改Dockerfile,增加端口暴露容器端口Expose:

FROM python

ENV APP_ROOT=/src/code
WORKDIR ${APP_ROOT}/

COPY . ${APP_ROOT}/

RUN pip install Flask -i https://pypi.tuna.tsinghua.edu.cn/simple
RUN pip install redis -i https://pypi.tuna.tsinghua.edu.cn/simple

EXPOSE 80

CMD python main.py

删除旧compose_web镜像,下次docker-compose up时会重新打包镜像:

docker rmi compose_web

修改main.py端口为80(不改为80会导致负载均衡失败)

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=80, debug=True)

修改后的docker-compose.yaml:

version: '3'
services:
  web:
    build: .
    links:
        - redis
    environment:
        REDIS_HOST: redis
  redis:
    image: redis
  lib:
    image: dockercloud/haproxy
    ports:
        - 7777:80
    links:
        - web
    volumes:
        - /var/run/docker.sock:/var/run/docker.sock

启动并测试:

# 启动
[root@centos7 compose]# docker-compose up -d
Creating network "compose_default" with the default driver
Creating compose_redis_1 ... done
Creating compose_web_1   ... done
Creating compose_lib_1   ... done

# 查看容器
[root@centos7 compose]# docker ps
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS                                     NAMES
ec554f11a680        dockercloud/haproxy             "/sbin/tini -- doc..."   5 minutes ago       Up 5 minutes        443/tcp, 1936/tcp, 0.0.0.0:7777->80/tcp   compose_lib_1
60ea95907902        compose_web                     "/bin/sh -c 'pytho..."   5 minutes ago       Up 5 minutes        80/tcp                                    compose_web_1
b1bdff3e70e7        redis                           "docker-entrypoint..."   5 minutes ago       Up 5 minutes        6379/tcp                                  compose_redis_1

# 测试
[root@centos7 compose]# curl http://127.0.0.1:7777/
Hello! Incr num is 1, hostname:60ea95907902
[root@centos7 compose]# curl http://127.0.0.1:7777/
Hello! Incr num is 2, hostname:60ea95907902


容器扩容

[root@centos7 compose]# docker-compose up --scale web=3 -d
compose_redis_1 is up-to-date
Starting compose_web_1 ... done
Creating compose_web_2 ... done
Creating compose_web_3 ... done
compose_lib_1 is up-to-date

[root@centos7 compose]# docker ps
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS                                     NAMES
761485161b6f        compose_web                     "/bin/sh -c 'pytho..."   22 seconds ago      Up 21 seconds       80/tcp                                    compose_web_3
af8e33b80771        compose_web                     "/bin/sh -c 'pytho..."   22 seconds ago      Up 21 seconds       80/tcp                                    compose_web_2
ec554f11a680        dockercloud/haproxy             "/sbin/tini -- doc..."   8 minutes ago       Up 8 minutes        443/tcp, 1936/tcp, 0.0.0.0:7777->80/tcp   compose_lib_1
60ea95907902        compose_web                     "/bin/sh -c 'pytho..."   8 minutes ago       Up 8 minutes        80/tcp                                    compose_web_1
b1bdff3e70e7        redis                           "docker-entrypoint..."   8 minutes ago       Up 8 minutes        6379/tcp                                  compose_redis_1

访问测试,可发现每次hostname对应不同容器CONTAINER ID:

[root@centos7 compose]# curl http://127.0.0.1:7777/
Hello! Incr num is 3, hostname:60ea95907902
[root@centos7 compose]# curl http://127.0.0.1:7777/
Hello! Incr num is 4, hostname:af8e33b80771
[root@centos7 compose]# curl http://127.0.0.1:7777/
Hello! Incr num is 5, hostname:761485161b6f
[root@centos7 compose]# curl http://127.0.0.1:7777/
Hello! Incr num is 6, hostname:60ea95907902
[root@centos7 compose]# curl http://127.0.0.1:7777/
Hello! Incr num is 7, hostname:af8e33b80771

容器减少至1个:

[root@centos7 compose]# docker-compose up --scale web=1 -d
compose_redis_1 is up-to-date
Stopping and removing compose_web_2 ... done
Stopping and removing compose_web_3 ... done
Starting compose_web_1              ... done
compose_lib_1 is up-to-date
[root@centos7 compose]# docker ps
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS                                     NAMES
ec554f11a680        dockercloud/haproxy             "/sbin/tini -- doc..."   10 minutes ago      Up 10 minutes       443/tcp, 1936/tcp, 0.0.0.0:7777->80/tcp   compose_lib_1
60ea95907902        compose_web                     "/bin/sh -c 'pytho..."   10 minutes ago      Up 10 minutes       80/tcp                                    compose_web_1
b1bdff3e70e7        redis                           "docker-entrypoint..."   10 minutes ago      Up 10 minutes       6379/tcp                                  compose_redis_1

依然可以正常访问,且hostname无变化:

[root@centos7 compose]# curl http://127.0.0.1:7777/
Hello! Incr num is 9, hostname:60ea95907902
[root@centos7 compose]# curl http://127.0.0.1:7777/
Hello! Incr num is 10, hostname:60ea95907902
[root@centos7 compose]# curl http://127.0.0.1:7777/
Hello! Incr num is 11, hostname:60ea95907902



docker run -v

作用:挂载宿主机的一个目录

docker run -v /宿主机目录:/容器目录 镜像名

练习:

  1. 将mysql容器目录挂载到宿主机
  2. 在容器内创建数据
  3. 删除该容器
  4. 运行新的mysql容器,并挂载之前的宿主目录
  5. 查看在旧容器创建的数据,可发现数据依然在
# 1.启动名为mysql_test容器
# -e MYSQL_ALLOW_EMPTY_PASSWORD=true设置mysql无密码
[root@centos7 test]# docker run -d -v mysql:/var/lib/mysql --name mysql_test -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
9c30284048ed314f0cce950b7d7d5a421b0caeb755d34524ad411e81cadf6155

[root@centos7 test]# docker ps
CONTAINER ID        IMAGE                           COMMAND                  CREATED              STATUS              PORTS                      NAMES
9c30284048ed        mysql                           "docker-entrypoint..."   About a minute ago   Up 58 seconds       3306/tcp, 33060/tcp        mysql_test

# 查看挂载路径及新建mysql挂载目录
[root@centos7 volumes]# pwd
/var/lib/docker/volumes
[root@centos7 volumes]# ls | grep mysql
mysql

# 2.进入容器,创建名为docker的database数据
[root@centos7 test]# docker exec -it mysql_test /bin/bash
root@9c30284048ed:/# mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.24 MySQL Community Server - GPL

mysql> create database docker;
Query OK, 1 row affected (0.05 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| docker             |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.01 sec)

# 3.删除该容器
[root@centos7 test]# docker stop mysql_test
mysql_test
[root@centos7 test]# docker rm mysql_test
mysql_test

# 4.运行新的mysql容器,并挂载之前的宿主目录
[root@centos7 test]# docker run -d -v mysql:/var/lib/mysql --name mysql_test2 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
c02cde00724df9630d5bc3088c1ae2486e38108033f57d34f73f7ac834be267f
[root@centos7 test]# docker ps
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS                      NAMES
c02cde00724d        mysql                           "docker-entrypoint..."   5 seconds ago       Up 4 seconds        3306/tcp, 33060/tcp        mysql_test2

# 5.进入新建容器mysql_test2,查看名为docker的database是否存在
[root@centos7 test]# docker exec -it mysql_test2 /bin/bash
root@c02cde00724d:/# mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.24 MySQL Community Server - GPL

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| docker             |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.02 sec)



Dockerfile Volume指令与docker -v的区别

Dockerfile中的VOLUME指令实际使用中是不是就是跟docker run中的-v参数一样是将宿主机的一个目录绑定到容器中的目录以达到共享目录的作用呢?

并不然,其实VOLUME指令只是起到了声明了容器中的目录作为匿名卷,但是并没有将匿名卷绑定到宿主机指定目录的功能。

但是当我们生成镜像的Dockerfile中以Volume声明了匿名卷,并且我们以这个镜像run了一个容器的时候,docker会在安装目录下的指定目录下面生成一个目录来绑定容器的匿名卷(这个指定目录不同版本的docker会有所不同)。

简单来说,就是我们在docker run 没有显示-v指定挂载时,会自动将Dockerfile中Volume指定目录挂载在/var/lib/docker/volumes目录下

举例:

FROM java:8
VOLUME /tmp /usr/tmp  # VOLUME /tmp /usr/tmp将容器中的 /tmp 和/usr/tmp目录映射到宿主机的目录
COPY /target/springbootdemo.jar app.jar
RUN bash -c 'touch /app.jar'
EXPOSE 10001
ENTRYPOINT ["java","-jar","/app.jar"]

运行后:

docker inspect add8a379065c

"Mounts": [
            {
                "Type": "volume",
                "Name": "3c18486ccfe419156ef62d346d29f6668ec34a236497c47f7e7907e95c310d0e",
                "Source": "/var/lib/docker/volumes/3c18486ccfe419156ef62d346d29f6668ec34a236497c47f7e7907e95c310d0e/_data",
                "Destination": "/tmp",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            },
            {
                "Type": "volume",
                "Name": "c5b6e1e0f6db6e70f15d836caa9663173e4bd8e23db1817146c31348d931a43b",
                "Source": "/var/lib/docker/volumes/c5b6e1e0f6db6e70f15d836caa9663173e4bd8e23db1817146c31348d931a43b/_data",
                "Destination": "/usr/tmp",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ]



版权声明:本文为ihaha233原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。