docker images
# 镜像名: ubuntu-with-vi
docker build -t ubuntu-with-vi
特定镜像名 由
repository
:tag
构成 注意:tag
为latest
并无特殊含义,仅仅是 未指明 镜像tag
时,Docker 会使用 默认值latest
而已 尽管 Docker Hub 上很多repository
将latest
作为 最新稳定版本 别名,但这仅仅是约定,非强制规定
docker build -t yiyungent/uhub .
注意:repository name must be lowercase 镜像名必须小写 最后有个 点 . 表示从当前路径找 Dockerfile 文件进行构建
docker tag oldImageName [username]/xxx:tag
# 举例
docker tag ubuntu yiyungent/my-ubuntu:v1
[username]/ 部分非必需,如果要上传到 Docker Hub,
repository
则需有用户名部分
docker push yiyungent/my-ubuntu:v1
docker pull yiyungent/my-ubuntu:v1
docker history my-ubuntu
docker commit # TODO: 待添加参数
Dockerfile
构建镜像docker build
tag
docker tag my-ubuntu yiyungent/my-ubuntu:v1
Docker host
中的镜像docker rmi my-ubuntu
Docker Hub
中的镜像docker search ubuntu
# 以下两条等价:查看 正在运行 的容器
docker ps
docker container ls
# 以下两条等价:查看 所有状态 的容器
docker ps -a
docker container ls -a
容器的
生命周期
依赖于启动时执行的命令
,只要该命令不结束,容器就不会退出
docker run
# attach 到 容器启动命令 的终端
docker attach <container>
docker exec -it <container> bash|sh
参考:
docker cp container_id:<docker容器内的路径> <本地保存文件的路径>
docker cp 10704c9eb7bb:/root/test.text /home/vagrant/test.txt
注意: 上方此种写法, 必须要求
/home/vagrant/test.txt
已存在, 然后会被覆盖
docker cp 本地文件的路径 container_id:<docker容器内的路径>
docker cp /home/vagrant/test.txt 10704c9eb7bb:/root/test.text
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH
docker cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH
假设路径分隔符为/
,第一个参数为SRC_PATH
,第二个参数为DEST_PATH
,行为如下:
SRC_PATH
指定一个文件DEST_PATH
不存在DEST_PATH
DEST_PATH
不存在并以/
DEST_PATH
存在并且是一个文件DEST_PATH
存在并且是一个目录SRC_PATH
SRC_PATH
指定目录DEST_PATH
不存在DEST_PATH
被创建为一个目录,并且源目录的内容被复制到这个目录中DEST_PATH
存在并且是一个文件DEST_PATH
存在并且是一个目录SRC_PATH
不以/.
(即:斜线后跟点) 结尾SRC_PATH
确实以/.
(即:斜线后跟点) 结尾# 登陆账号,用于上传镜像到 Docker Hub
docker login -u username
上传到 Docker Hub,需将 镜像的
repository
部分 与Docker Hub用户名
相匹配 完整镜像名:[username]/xxx:tag
补充:Docker 官方自己维护的镜像无用户名部分
参考:
docker run --name demo-mysql-container -v /home/mysql_data:/var/lib/mysql -p 3307:3306 -e MYSQL_ROOT_PASSWORD=demo-root-pw -e MYSQL_DATABASE=demodb -d mysql
--name 指定容器名 demo-mysql-container
-v 将宿主机 /home/mysql_data
挂载到 容器内 /var/lib/mysql
目录
挂载:可以理解为 将
/home/mysql_data
与/var/lib/mysql
连接了起来,成为了一块共享区域,在宿主机修改/home/mysql_data
等同 修改容器内/var/lib/mysql
,反之亦然。
-p 将宿主机 3307 映射到 容器内 3306 端口
注意:docker容器内 mysql实例 默认监听3306端口,所以一定是映射到容器内 3306端口, 如需修改默认端口,需修改mysql容器内mysql配置文件
/etc/mysql/conf.d
,一般来说这没有必要,容器彼此之间是隔离的,不存在端口占用情况,但如果宿主机 3306端口被占用,就不能映射到宿主机3306了,所以这里是 3307:3306
-e 后为环境变量(Environment Variables)
MYSQL_ROOT_PASSWORD=demo-root-pw
MySQL 的 root 用户密码为:demo-root-pw
MYSQL_DATABASE=demodb
在镜像创建为容器启动时,将创建一个名为 demodb
的数据库,当存在MySQL用户时,此用户将拥有对此数据库的 superuser
权限。
-d 在后台运行
最后的 mysql 为 使用官方 mysql 镜像,可使用 mysql:tagName
指定标签版本。
补充:
在当前目录下挂载 MySQL 数据目录,利用 $PWD
变量
-v "$PWD/mysql_data":/var/lib/mysql
补充:
通过命令指定字符编码,而无需更改 MySQL配置文件
docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
即
--character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
docker-compose.yml
version: '3.1'
services:
demo-mysql-service:
container_name: demo-mysql-container
image: mysql
command: --default-authentication-plugin=mysql_native_password
ports:
- 3307:3306
restart: always
environment:
MYSQL_ROOT_PASSWORD: demo-root-pw
MYSQL_DATABASE: demodb
networks:
- demo-network
demo-web-service:
container_name: demo-web-container
build:
context: .
dockerfile: Dockerfile
ports:
- 8080:5000
restart: always
networks:
- demo-network
networks:
demo-network:
driver: bridge
docker system df
<none>:<none>
镜像docker image prune
docker system prune
driver failed programming external connectivity on endpoint simcaptcha-container
ERROR: for simcaptcha-container Cannot start service simcaptcha.service: driver failed programming external connectivity on endpoint simcaptcha-container (dc434a8d5611ac961ad5212403a826fe8ea3943a69227b400e6fc11d7469752f): Bind for 0.0.0.0:5004 failed: port is already allocated
解决:
重启docker
systemctl restart docker
参考:
privileged: true
user: root
privileged: true
大约在0.6版,privileged 被引入 Docker。 使用该参数,container内的 root 拥有真正的 root 权限。 否则,container 内的 root 只是外部的一个普通用户权限。 privileged 启动的容器,可以看到很多 host 上的设备,并且可以执行 mount。 甚至允许你在 docker 容器中启动 docker 容器。user: root
通过 user 指令限定了缺省用户, 进入之后直接显示的是root 用户
version: '3.4'
services:
plugincore.service:
image: yiyungent/plugincore-aspnetcore3-1
container_name: plugincore-aspnetcore3-1-container
ports:
- "5007:80"
privileged: true
user: root
restart: always
补充:
对应
docker run --user root --privileged=true
Volume 可以叫做
数据卷
,可供一个或者多个容器使用: - 数据卷 可以在容器之间共享和重用 - 对 数据卷 的修改会立马生效 - 对 数据卷 的更新,不会影响镜像 - 数据卷 默认会一直存在,即使容器被删除
这里说的备份指的是直接从本地备份镜像文件,可以使用 docker save 命令将镜像打包成 tar 文件,之后可以使用 docker load 命令来恢复。
docker save -o /path/to/image.tar image-name:1.0.0
docker load -i /path/to/image.tar
备份容器有不同的方法:
需要注意的是所有的命令都只会备份容器 layered file system ,不包括 挂载的数据卷 Volumes
Docker user guide 中有非常详细的知道,如何备份数据卷,这样就可以在新容器启动时使用备份好的数据。当备份 data volume 时,需要先关闭容器。
docker volume create my-vol # 创建数据卷
docker volume ls # 查看所有数据卷
docker volume inspect my-vol # 查看指定数据卷内容
docker run -d -P \
--name web \
# -v my-vol:/wepapp \
--mount source=my-vol,target=/webapp \
training/webapp \
python app.py # 启动并挂载一个数据卷 使用 `--mount`
docker inspect web # 查看容器中 mount 信息
docker volume rm my-vol # 移除数据卷
数据卷
是被设计用来持久化数据的,它的生命周期独立于容器,Docker 不会在容器被删除后自动删除 数据卷,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的 数据卷。如果需要在删除容器的同时移除数据卷。可以在删除容器的时候使用 docker rm -v
这个命令。
无主 (dangling) 的数据卷可能会占据很多空间,要清理请使用以下命令
docker volume prune
比如在 docker compose 中定义了叫做 db_data
的 volume:
volumes:
db_data:
那么在启动 docker compose 之后会生成一个 DOCKER_COMPOSE_NAME
加上 VOLUME_NAME
的容器卷
[DOCKER_COMPOSE_NAME]_[VOLUME_NAME]
那么可以使用下面的命令来备份该数据卷:
docker run --rm \
--volume [DOCKER_COMPOSE_PREFIX]_[VOLUME_NAME]:/[TEMPORARY_DIRECTORY_TO_STORE_VOLUME_DATA] \
--volume $(pwd):/[TEMPORARY_DIRECTORY_TO_STORE_BACKUP_FILE] \
alpine \
tar cvf /[TEMPORARY_DIRECTORY_TO_STORE_BACKUP_FILE]/[BACKUP_FILENAME].tar /[TEMPORARY_DIRECTORY_TO_STORE_VOLUME_DATA]
看清楚其中的临时 DATA 目录和 临时备份目录,执行该命令之后,在当前文件夹下就会产生 BACKUP_FILENAME.tar
这样的文件,里面包含数据卷中的内容。
这一行语句包含两个 volume,举例使用说明,假如有一个数据卷叫做 chevereto_chevereto_data
,要备份该数据卷:
docker run --rm \
--volume chevereto_chevereto_data:/tmp \
--volume $(pwd):/path_to_store_backup \
alpine \
tar cvf /path_to_store_backup/chevereto_chevereto_data.tar /tmp
那么就能够使用该命令来恢复数据卷数据:
docker run --rm \
--volume [DOCKER_COMPOSE_PREFIX]_[VOLUME_NAME]:/[TEMPORARY_DIRECTORY_STORING_EXTRACTED_BACKUP] \
--volume $(pwd):/[TEMPORARY_DIRECTORY_TO_STORE_BACKUP_FILE] \
alpine \
tar xvf /[TEMPORARY_DIRECTORY_TO_STORE_BACKUP_FILE]/[BACKUP_FILENAME].tar -C /[TEMPORARY_DIRECTORY_STORING_EXTRACTED_BACKUP] --strip 1
恢复数据卷数据,举例:
docker run --rm \
--volume chevereto_chevereto_data:/tmp \
--volume $(pwd):/path_to_store_backup \
alpine \
tar xvf /path_to_store_backup/chevereto_chevereto_data.tar -C /tmp --strip 1
如果是数据库容器,比如 MySQL 容器,备份数据可以使用如下方式
docker exec [CONTAINER_NAME] /usr/bin/mysqldump -u root --password=root [DATABASE] > backup.sql
然后使用下面的命令来恢复
cat backup.sql | docker exec -i [CONTAINER_NAME] /usr/bin/mysql -u root --password=root [DATABASE]
对于 docker compose 启动的多个容器,可能因为宿主机器变化而导致 docker 容器的 id 有变化,可能在回复数据之后,还需要对数据库连接的地址进行修改才能完整的恢复。
docker version # 查看版本信息
docker info # 显示统信息,包括镜像和容器数
docker images # 查看镜像 (docker images -a 含中间镜像层)
docker rmi 镜像ID # 删除单个镜像
docker rmi -f 镜像ID # 强制 删除单个镜像
docker rm 容器ID # 删除单个容器
docker run -it REPOSITORY bash 启动镜像
--name="容器新名字": 为容器指定一个名称;
-d: 后台运行容器,并返回容器ID,也即启动守护式容器;
-i:以交互模式运行容器,通常与 -t 同时使用;
-t:为容器重新分配一个伪输入终端,通常与 -i 同时使用;
-P: 随机端口映射;
-p: 指定端口映射;
# 进入容器, 并新开 Terminal 执行 bash
docker exec -it 容器ID bash
docker ps # 查看正在运行容器
docker ps -a # 查看所有容器
docker start 容器ID或者容器名 # 启动容器
docker restart 容器ID或者容器名 # 重启容器
docker stop 容器ID或者容器名 # 停止容器
docker kill 容器ID或者容器名 # 强制停止容器
docker kill $(docker ps -a -q) # 停用全部运行中的容器
docker rm $(docker ps -aq) # 删除全部容器
docker rmi `docker images -q` # 删除所有镜像
ps -ef|grep 容器ID
top -p 7358(pid)
参数说明: -
PID
:进程的ID -USER
:进程所有者 -PR
:进程的优先级别,越小越优先被执行 -NInice
:值 -VIRT
:进程占用的虚拟内存 -RES
:进程占用的物理内存 -SHR
:进程使用的共享内存 -S
:进程的状态。S表示休眠,R表示正在运行,Z表示僵死状态,N表示该进程优先值为负数 -%CPU
:进程占用CPU的使用率 -%MEM
:进程使用的物理内存和总内存的百分比 -TIME+
:该进程启动后占用的总的CPU时间,即占用CPU使用时间的累加值。 -COMMAND
:进程启动命令名称
top
命令经常用来监控 linux 的系统状况,是常用的性能分析工具,能够实时显示系统中各个进程的资源占用情况。
/bin/bash: /bin/bash: cannot execute binary file
# ...
ENTRYPOINT ["/bin/bash"]
这样做后,会导致
docker run -it --name bayes-svm-knn-container bayes-svm-knn /bin/bash
报错:
/bin/bash: /bin/bash: cannot execute binary file
cd /root/bayes-svm-knn
docker run -d -it --name bayes-svm-knn-container -v ${PWD}/code:/app/code -v ${PWD}/data:/app/data bayes-svm-knn bash
注意 一定要加上
-d -it bash
, 这样容器才不会自动退出, 如果docker attach bayes-svm-knn-container
进入主进程 bash 后,再Ctrl+D
则会导致主线程退出,容器结束, 可以使用Ctrl+P+Q
退出而不终止容器运行,docker exec -it bash
的方式是新开 Session 终端, 因此Ctrl+D
不会终止容器运行PS:
docker -v
中 host 不能使用 相对路径, 必须使用 绝对路径, 但在docker-compose.yml
就可以使用相对路径
docker exec -it bayes-svm-knn-container bash
参考:
docker-compose.yml
配置文件 常用详解/bin/bash -c
参考:
-c
命令表示后面的参数将会作为字符串读入 作为执行的命令
举个例子,尝试在本地执行下面两个命令:
/bin/bash -c ls
/bin/bash ls
可以看到, /bin/bash -c
后面接 命令 ,而 /bin/bash
后面接 执行的脚本。
注意: 如果后面的命令有空格, 则用引号括起来, 例如
/bin/bash -c "ls /root"
对于一个合法的容器的名称来说只可以包括以下字符:小写字母a~z
、大写字母A-Z
、数字0~9
、下划线
、圆点
、横线
docker-compose.yml
中 build.context
- me/
- code/
- Dockerfile
- docker-compose.yml
- requirements.txt
cd me/code
docker-compose up -d
docker-compose.yml
version: '3.1'
services:
# 朴素贝叶斯
train_bayes_bnb_model_bag:
build:
context: ../
dockerfile: ./code/Dockerfile
container_name: train_bayes_bnb_model_bag-container
image: train_bayes_bnb_model_bag
entrypoint: /bin/bash -c "cd /app/code/train_scripts && python train_bayes_bnb_model_bag.py"
volumes:
- ../code:/app/code
- ../data:/app/data
此时,
build.context
即 通过../
跳出此层, 于是在me/
注意:
build.dockerfile
路径相对于build.context
所指定的路径
注意: Dockerfile
中的源路径 也是 相对于 build.context
的路径 > Dockerfile
WORKDIR /app
RUN mkdir code data
COPY ["./code/requirements.txt", "./code"]
注意:
docker-compose.yml
中volumes
宿主机路径 是相对于 执行docker-compose up
处的路径, 而不是build.context
路径
PS:
- 想避免一些路径问题, 可以指定 docker-compose.yml
路径,如下方:
docker-compose -f ./code/docker-compose.yml up -d
docker-compose.yml
限制内存, CPU参考:
docker-compose
对单个服务的操作参考:
docker-compose.yml
内单个服务docker-compose up -d train_bayes_bnb_model_bag