在虚拟化技术成熟的今天,用户不仅仅满足于OS级别的虚拟化机制,它们需要的是更小、更快速的服务扩展方式,虚拟机会重新创建一个虚拟OS,所以无论是占用空间、运行速度上都要慢得多。
相比之下Docker是将一个个服务、应用程序打包,直接用宿主底层的操作系统来进行运行,但是将资源隔离开来,实现了高效地利用。
以下是Ubuntu18.04的安装过程:
$ sudo apt-get remove docker docker-engine docker.io containerd runc
首先需要安装一些需要的依赖包,如果确认已经都安装过,就可以跳过。
# 更新源列表
$ sudo apt-get update
# 安装所需依赖
$ sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
然后添加官方库的GPG密钥:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
可以查看是否添加成功,通过搜索指纹的后8位:
$ sudo apt-key fingerprint 0EBFCD88
pub rsa4096 2017-02-22 [SCEA]
9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88
uid [ unknown] Docker Release (CE deb) <[email protected]>
sub rsa4096 2017-02-22 [S]
添加Docker仓库:
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
然后更新以下源列表,再进行安装:
# 更新源列表
$ sudo apt-get update
# 安装docker-ce
$ sudo apt-get install docker-ce
检查安装是否成功:
$ sudo docker version
Client: Docker Engine - Community
Version: 19.03.5
API version: 1.40
Go version: go1.12.12
Git commit: 633a0ea838
Built: Wed Nov 13 07:29:52 2019
OS/Arch: linux/amd64
Experimental: false
......
......
或者直接运行:
$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
9bb5a5d4561a: Pull complete
Digest: sha256:3e1764d0f546ceac4565547df2ac4907fe46f007ea229fd7ef2718514bcec35d
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
......
上述信息说明,一开始没有找到hello-world的镜像,所以需要从默认仓库拉取,拉取完之后,创建了一个容器,然后在里面执行了程序,看到输出了一个Hello from Docker的信息。此时可以看到成功安装了Docker并且创建了第一个容器来运行。
如果不使用sudo,直接执行docker命令的话,我们会看到一些错误信息,如下所示:
$ docker version
Client: Docker Engine - Community
Version: 19.03.5
API version: 1.40
Go version: go1.12.12
Git commit: 633a0ea838
Built: Wed Nov 13 07:29:52 2019
OS/Arch: linux/amd64
Experimental: false
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.40/version: dial unix /var/run/docker.sock: connect: permission denied
因为当前用户没有足够的权限,所以需要在前面加上sudo,可是这样就十分不方便,每次输指令都需要sudo一下。
这是因为,默认情况下,该docker命令只能由root用户或docker组中的用户运行,该用户在Docker的安装过程中自动创建。
解决办法就是,将当前用户加入docker组当中去。
$ sudo usermod -aG docker ${USER}
将指定的用户加入用户组中去,然后注销重新登陆一下,就可以不使用sudo来执行docker的指令了。
刚刚我们已经成功创建并且运行了hello-world的应用。
现在尝试一些别的。
使用search可以搜索镜像库中存在的镜像列表:
$ docker search ubuntu
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
ubuntu Ubuntu is a Debian-based Linux operating sys鈥� 10271 [OK]
dorowu/ubuntu-desktop-lxde-vnc Docker image to provide HTML5 VNC interface 鈥� 370 [OK]
rastasheep/ubuntu-sshd Dockerized SSH service, built on top of offi鈥� 236 [OK]
consol/ubuntu-xfce-vnc Ubuntu container with "headless" VNC session鈥� 199 [OK]
ubuntu-upstart Upstart is an event-based replacement for th鈥� 102 [OK]
ansible/ubuntu14.04-ansible Ubuntu 14.04 LTS with ansible 98 [OK]
neurodebian NeuroDebian provides neuroscience research s鈥� 62 [OK]
1and1internet/ubuntu-16-nginx-php-phpmyadmin-mysql-5 ubuntu-16-nginx-php-phpmyadmin-mysql-5 50
可以选择自己想要的版本进行拉取,这里选用默认的:
$ docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
6b98dfc16071: Pull complete
4001a1209541: Pull complete
6319fc68c576: Pull complete
b24603670dc3: Pull complete
97f170c87c6f: Pull complete
Digest: sha256:5f4bdc3467537cbbe563e80db2c3ec95d548a9145d64453b06939c4592d67b6d
Status: Downloaded newer image for ubuntu:latest
通过指令查看本地镜像列表:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 775349758637 6 weeks ago 64.2MB
hello-world latest fce289e99eb9 11 months ago 1.84kB
$ docker run -it ubuntu
# 进入到容器的ubuntu环境中
root@d50fe7bde791:/#
注意到的是,虽然容器使用的版本是Ubunut16.04,但是内核还是会使用宿主机的内核(区别于虚拟化技术),所以即使查看内核,还是会显示当前宿主机的内核信息。
root@d50fe7bde791:/# uname -a
Linux d50fe7bde791 5.0.0-37-generic #40~18.04.1-Ubuntu SMP Thu Nov 14 12:06:39 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
然后就可以在这个容器里面执行一些基本命令来测试了。
使用docker container
查看帮助:
$ docker container
Usage: docker container COMMAND
Manage containers
Commands:
attach Attach local standard input, output, and error streams to a running container
commit Create a new image from a container's changes
cp Copy files/folders between a container and the local filesystem
create Create a new container
diff Inspect changes to files or directories on a container's filesystem
exec Run a command in a running container
export Export a container's filesystem as a tar archive
inspect Display detailed information on one or more containers
kill Kill one or more running containers
logs Fetch the logs of a container
ls List containers
pause Pause all processes within one or more containers
port List port mappings or a specific mapping for the container
prune Remove all stopped containers
rename Rename a container
restart Restart one or more containers
rm Remove one or more containers
run Run a command in a new container
start Start one or more stopped containers
stats Display a live stream of container(s) resource usage statistics
stop Stop one or more running containers
top Display the running processes of a container
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
wait Block until one or more containers stop, then print their exit codes
可以看到基本上跟进程的操作类似,主要掌握起、停、查看状态、连接几个基本操作;
实际上,并不需要加container命令参数,docker指令本身也能够执行这些命令,如:
docker ps
== docker container ls
docker start ${CONTAINER} == docker container start ${CONTAINER}
docker attach ${CONTAINER} == docker container attach ${CONTAINER}
下面就以刚刚运行的ubuntu容器做例子:
# 在退出了ubuntu容器之后,进程也自动停止了,所以这里不能够看到
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d50fe7bde791 ubuntu "bash" 24 hours ago Exited (127) About an hour ago beautiful_mestorf
9c053d7c27ad hello-world "/hello" 24 hours ago Exited (0) 24 hours ago happy_ellis
可以看到之前创建的两个容器,但是状态都是停止的。
现在可以先启动容器,通过其ID或者是名字:
# docker start beautiful_mestorf
$ docker start d50fe7bde791
d50fe7bde791
# 连接到容器
$ docker attach d50fe7bde791
root@d50fe7bde791:/#
然后就能像刚刚那样去终端调试它了。
对于不想要的容器,可以使用rm来删除它(两种命令方式,我比较喜欢简洁一点的):
# $ docker container rm d50fe7bde791
$ docker rm d50fe7bde791
使用docker image
查看帮助:
$ docker image
Usage: docker image COMMAND
Manage images
Commands:
build Build an image from a Dockerfile
history Show the history of an image
import Import the contents from a tarball to create a filesystem image
inspect Display detailed information on one or more images
load Load an image from a tar archive or STDIN
ls List images
prune Remove unused images
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rm Remove one or more images
save Save one or more images to a tar archive (streamed to STDOUT by default)
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
跟之前一样有一些指令是不需要加image这个参数的:
如:
docker images
== docker image ls
docker rmi ${IMAGE}
== docker image rm ${IMAGE}
使用history可以查看对镜像执行过什么操作。
这里解释一下,因为镜像的组成过程中是一层一层往上套的,比如说,在ubuntu镜像创建的容器里,安装一些基本的软件如vim等,然后把这个容器构建成一个新的镜像,这时候这个镜像就相当于在ubuntu镜像的基础上运行了几条指令。
下面进行测试,首先进入ubuntu容器,然后安装几个软件(Ubuntu基本使用,这里不展开说明),结束之后,回到自己的终端,使用docker commit ${container_id} ${image_name}
创建一个新的镜像:
$ docker commit d50fe7bde791 test
sha256:97c46372fe797e69871fff1741af09bfecb73ffda236d81e12f1d54635fe9e16
hsy@ubuntu:~$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
test latest 97c46372fe79 15 seconds ago 245MB
ubuntu latest 775349758637 6 weeks ago 64.2MB
hello-world latest fce289e99eb9 11 months ago 1.84kB
可以看到比初始的镜像大了很多,因为装了几个软件的原因。
然后可以通过history来查看这个构建的过程:
$ docker history test
IMAGE CREATED CREATED BY SIZE COMMENT
97c46372fe79 3 minutes ago bash 181MB
775349758637 6 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 6 weeks ago /bin/sh -c mkdir -p /run/systemd && echo 'do… 7B
6 weeks ago /bin/sh -c set -xe && echo ' #!/bin/sh' > /… 745B
<missing> 6 weeks ago /bin/sh -c [ -z "$(apt-get indextargets)" ] 987kB
<missing> 6 weeks ago /bin/sh -c #(nop) ADD file:a48a5dc1b9dbfc632… 63.2MB
可以看到第二个image的id就是ubuntu的ID,就是说明,这个镜像是从ubuntu镜像的基础上执行了一些命令,套了一个新的层来构建的。
docker默认网关是172.17.0.1,然后创建容器的时候,会默认自动分配给172.17.0.2.。。。这样的地址,是因为子网的设置就是172.17.0.0/16,
通过docker network create XXX
可以创建新的网桥,然后在创建容器的时候可以指定分配IP,或所使用的网络:
$ docker run --name u1 --net mynet -it -p 8080:80 --rm ubuntu-aliyun_source:net
$ docker run --name u2 --net mynet -it --rm ubuntu-aliyun_source:net
--net
指定所使用的网桥-p
指定容器端口与网桥端口的映射关系,类似NAT的变换。首先到Registry上拉取mysql的镜像,拉取方式之前已经讲过了。
然后启动:
# 服务端
$ docker run -p 3306:3306 --name mysql2 -e MYSQL_ROOT_PASSWORD=root -d mysql
# 客户端
$ docker run -it --net host mysql:5.7 "sh"
$ mysql -h127.0.0.1 -P3306 -uroot -proot
这样可以连上服务器。
创建叫mydb的volumn
$ docker rm $(docker ps -a -q) -f -v
$ docker volume create mydb
$ docker volume ls
DRIVER VOLUME NAME
local 39898de78ce82ac68d13ccd7bb00aa5f58ddceacf86d88339c002ac6ffbf879f
local mydb
将自己定义的volumn挂载到相应的目录下,创建数据库容器
$ docker run --name mysql2 -e MYSQL_ROOT_PASSWORD=root -v mydb:/var/lib/mysql -d mysql
使用客户端连接:
$ docker run --name myclient --link mysql2:mysql -it mysql bash
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.18 MySQL Community Server - GPL
Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> ...
本次实验先到这里,之后继续学习docker的知识。
初次学习,有很多概念都不太懂,现在先总结一下。如有错误,请指正,谢谢!