0%

1
2
3
4
5
6
# 停止docker
docker stop $(docker ps -a | grep "Exited" | awk '{print $1 }')
# 删除docker
docker rm $(docker ps -a | grep "Exited" | awk '{print $1 }')
# 删除images
docker rmi $(docker images | grep "none" | awk '{print $3}')

参考链接

https://www.jianshu.com/p/d06830de219f

背景

生命不息,折腾不止。在老家布置了一台服务器用于家庭影音中心,现在在新家,与老家相隔3000多公里,但是新家的服务器因为新装一无所有。此时此刻,突发奇想,我怎么能把老家的服务器里下载好的资源同步到新家的服务器上?

解决方案:

    1. 把老家服务器搬过来
    1. 从新家访问老家的NAS,然后通过HTTP下载
    1. 自己写个同步程序部署在两台服务器上
    1. 或许可以用BT下载的方式从老家下载过来

方案1直接pass。

方案2虽然也可以,但是群晖的连接好像直接复制到Aria2里下载不了,我可忍受不了下载一部50G的电影用浏览器自带的下载工具,而且还没有进度提示

方案3,emmmm……等有空再说

方案4,自己假设一台BT Trakcer服务器,然后做个种子下载,目前能想到的一个最佳方案

查阅相关资料,看看有没有现成的工具可以使用。

Searching …

!!!可以使用 OpenTracker 这个现成的工具来搭建。

那么问题来了,为了不搞乱服务器的环境,有没有现成的Docker镜像?

Continue searching …

在笔者孜孜不倦的努力下,真的发现了有人已经做好了镜像。

直接拉取镜像

1
docker pull lednerb/opentracker-docker

那么接下来如何启动一个容器?,我推荐docker-compose

1
2
3
4
5
6
7
8
version: '3'
services:
opentracker:
image: lednerb/opentracker-docker
restart: unless-stopped
ports:
- 6969:6969
- 6969:6969/udp

当然你也可以直接

1
docker run -dit --name opentracker -p 6969:6969/udp -p 6969:6969 lednerb/opentracker-docker

好了。大功告成。

那么我怎么知道它运行了没有,怎么查看状态?

举个栗子,比如我假设在了yourhostname.com这台主机上,那么访问

1
http://yourhostname.com:6969/state

或者访问更详细的内容

1
http://yourhostname.com:6969/state?mode=everything

即可看到这家伙有没有在认真工作咯!

20201224220240

emmmmm…..刚搭建好,还没传种子。

我们创建一个种子,传上去试试看。

创建种子的时候Tracker服务器填:

1
http://yourhostname.com:6969/announce

或者

1
udp://yourhostname.com:6969/announce

在Transmission里看一下。。。

20201224221255

一切OK。。。

到后台看一下

20201224221518

一切OK。。。可以看到已经增加了一个种子。

下载试试看。。

20201224222117

OK。。。已经出现一个peer了!

接下来就像下载BT一样,不过并不会有更多的peer出现,因为只有我自己在做种自己在下。。。

https://hub.docker.com/r/lednerb/opentracker-docker/

为了方便随时随地测试一些算法,做一些研究。笔者在自己的服务器上安装了jupyter-lab,这个是jupyter的下一代版本。但是因为不想搞乱自己服务器的环境,于是尝试寻找看看有没有jupyter的docker镜像,发现还真的有官方出的镜像。

官方出了很多镜像,根据不同的需求选择合适的镜像。本次搭建笔者选择了jupyter/datascience-notebook这个镜像,具体镜像列表参考:

https://jupyter-docker-stacks.readthedocs.io/en/latest/using/selecting.html

拉取镜像

1
docker pull jupyter/datascience-notebook

运行一个容器

1
docker run -p 8888:8888 jupyter/datascience-notebook
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
root@ubuntu:~# docker run -p 8888:8888 jupyter/datascience-notebook
Executing the command: jupyter notebook
[I 12:28:00.559 NotebookApp] Writing notebook server cookie secret to /home/jovyan/.local/share/jupyter/runtime/notebook_cookie_secret
[I 12:28:02.995 NotebookApp] JupyterLab extension loaded from /opt/conda/lib/python3.8/site-packages/jupyterlab
[I 12:28:02.996 NotebookApp] JupyterLab application directory is /opt/conda/share/jupyter/lab
[I 12:28:03.006 NotebookApp] Serving notebooks from local directory: /home/jovyan
[I 12:28:03.006 NotebookApp] Jupyter Notebook 6.1.5 is running at:
[I 12:28:03.007 NotebookApp] http://a0a0fecd00d5:8888/?token=2f725d16b757283384db037ff1707b590eca49d9ac037f3b
[I 12:28:03.007 NotebookApp] or http://127.0.0.1:8888/?token=2f725d16b757283384db037ff1707b590eca49d9ac037f3b
[I 12:28:03.007 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 12:28:03.019 NotebookApp]

To access the notebook, open this file in a browser:
file:///home/jovyan/.local/share/jupyter/runtime/nbserver-7-open.html
Or copy and paste one of these URLs:
http://a0a0fecd00d5:8888/?token=2f725d16b757283384db037ff1707b590eca49d9ac037f3b
or http://127.0.0.1:8888/?token=2f725d16b757283384db037ff1707b590eca49d9ac037f3b

访问你部署docker的那台主机,例如本次我部署在jupyter.local这台主机上,我们访问http://jupyter.local:8888会看到如下界面。

20201222203043

你可以使用token登录或使用token设置一个新密码。本次的token为2f725d16b757283384db037ff1707b590eca49d9ac037f3b

20201222203206

用token设置一个新密码然后登录。

20201222203257

这样就进来了。

但是这样我们的所有工作都在这个容器里,没有挂载外部的数据卷进来,当容器消失后我们的工作内容也将烟消云散。所以我们需要挂载外部的数据卷进来。

这里推荐使用docker-compose来启动容器,yaml格式的语法阅读非常清晰。

ubuntu 可以使用以下命令安装

1
apt install docker-compose -y

这里我们来看一个 docker compose 模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
version: "3.1"
services:
Jupyter:
image: jupyter/datascience-notebook:latest
tty: true
restart: always
container_name: jupyter
user: root
ports:
- "8888:8888"
volumes:
- "${PWD}/work:/home/jovyan/work"
environment:
- JUPYTER_ENABLE_LAB=yes
- GRANT_SUDO=yes
logging:
driver: "json-file"
options:
max-size: "100m"

在当前目录下新建一个work目录, 我们把这个目录挂载到容器里。
JUPYTER_ENABLE_LAB=yes启用jupyter-lab,这个是jupyter的下一代版本。

1
2
3
4
root@ubuntu:/home/naonao# mkdir work
root@ubuntu:/home/naonao# ls
work
root@ubuntu:/home/naonao#

例如我在/home/naonao这个目录下新建一个work文件夹,然后再本目录下创建一个docker-compose.yaml文件,复制上面的内容进去。

运行容器

1
docker-compose up
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
root@ubuntu:/home/naonao# nano docker-compose.yaml
root@ubuntu:/home/naonao# ls
docker-compose.yaml work
root@ubuntu:/home/naonao# docker-compose up
Creating network "naonao_default" with the default driver
Creating jupyter ... done
Attaching to jupyter
jupyter | Set username to: jovyan
jupyter | usermod: no changes
jupyter | Granting jovyan sudo access and appending /opt/conda/bin to sudo PATH
jupyter | Executing the command: jupyter lab
jupyter | [I 12:40:59.811 LabApp] Writing notebook server cookie secret to /home/jovyan/.local/share/jupyter/runtime/notebook_cookie_secret
jupyter | [I 12:41:00.953 LabApp] JupyterLab extension loaded from /opt/conda/lib/python3.8/site-packages/jupyterlab
jupyter | [I 12:41:00.954 LabApp] JupyterLab application directory is /opt/conda/share/jupyter/lab
jupyter | [I 12:41:00.957 LabApp] Serving notebooks from local directory: /home/jovyan
jupyter | [I 12:41:00.958 LabApp] Jupyter Notebook 6.1.5 is running at:
jupyter | [I 12:41:00.958 LabApp] http://051c0b8b860b:8888/?token=a37dc92a50b7b6f3fb0f01abfee6a374b5fb74d23a0a3114
jupyter | [I 12:41:00.958 LabApp] or http://127.0.0.1:8888/?token=a37dc92a50b7b6f3fb0f01abfee6a374b5fb74d23a0a3114
jupyter | [I 12:41:00.958 LabApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
jupyter | [C 12:41:00.963 LabApp]
jupyter |
jupyter | To access the notebook, open this file in a browser:
jupyter | file:///home/jovyan/.local/share/jupyter/runtime/nbserver-14-open.html
jupyter | Or copy and paste one of these URLs:
jupyter | http://051c0b8b860b:8888/?token=a37dc92a50b7b6f3fb0f01abfee6a374b5fb74d23a0a3114
jupyter | or http://127.0.0.1:8888/?token=a37dc92a50b7b6f3fb0f01abfee6a374b5fb74d23a0a3114

同刚才一样,你可以用token设置一个密码,或者也可以直接访问连接http://jupyter.local:8888/?token=a37dc92a50b7b6f3fb0f01abfee6a374b5fb74d23a0a3114,这里注意访问你部署docker的主机的地址,本例我部署在jupyter.local主机。我们将看到jupyer-lab的界面。

20201222204526

进入/work目录新建一个文件。

20201222204649

我的得到了一个Permission denied错误。

查阅资料发现

1
You must grant the within-container notebook user or group (NB_UID or NB_GID) write access to the host directory (e.g., sudo chown 1000 /some/host/folder/for/work).

https://jupyter-docker-stacks.readthedocs.io/en/latest/using/common.html

你必须允许容器的用户或组写你设置的这个目录

例如我挂载目录/home/naonao/work到容器里, 那么我需要更改这个目录的权限.chown 1000 /home/naonao/work

重启容器,问题解决。

20201222204942

1
2
3
4
root@ubuntu:/home/naonao# cd work
root@ubuntu:/home/naonao/work# ls
Untitled.ipynb
root@ubuntu:/home/naonao/work#

如果把它架设在公共云上,那么我们可以通过域名在任意位置访问到jupyter环境。

Nginx + SSL

通过Nginx反向代理并使用SSL加密HTTP

笔者用宝塔新建了一个静态网站,并设置了Let’s Encrpyt证书。
20201222205257

在华为云上部署docker,因为8888端口被占用,所以本次使用10000端口,在宝塔面板添加一个反向代理,当然你也可以自己配置Nginx。

20201222205721

完成单击配置文件

20201222210023

增加websocket

1
2
3
4
5
6
7
# websocket headers
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Scheme $scheme;

proxy_buffering off;

然后在点击左边目录的配置文件增加

1
2
3
4
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}

20201222205825

保存。

访问https://jupyter.wudinaonao.com一切正常

20201222210506

可能遇到的问题

Python3 connecting

有时候通过Nginx反向代理会出现可以访问界面但是无法连接到python,这是因为没有配置websocket导致。

通常出现在这种情况下,用户通过HTTPS访问Nginx的反向代理。即

user —https—> nginx —http—> docker

https://jupyter-docker-stacks.readthedocs.io/en/latest/using/selecting.html

https://jupyterhub.readthedocs.io/en/stable/reference/config-proxy.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/env bash

USERNAME="docker_username"
PASSWORD="docker_password"
ORGANIZATION="organization"
IMAGE="image"
TAG="tag"

login_data() {
cat <<EOF
{
"username": "$USERNAME",
"password": "$PASSWORD"
}
EOF
}

TOKEN=`curl -s -H "Content-Type: application/json" -X POST -d "$(login_data)" "https://hub.docker.com/v2/users/login/" | jq -r .token`

curl "https://hub.docker.com/v2/repositories/${ORGANIZATION}/${IMAGE}/tags/${TAG}/" \
-X DELETE \
-H "Authorization: JWT ${TOKEN}"

https://devopsheaven.com/docker/dockerhub/2018/04/09/delete-docker-image-tag-dockerhub.html

1.Singleton mode 单例模式

一个类最多创建一个实例

装饰器实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 装饰器实现
def singleton(class_):
instances = {}
def getInstance(*args, **kwargs):
if class_ not in instances:
instances[class_] = class_(*args, **kwargs)
return instances[class_]
return getInstance


@singleton
class MyClass(object):

pass

元类实现

1
2
3
4
5
6
7
8
9
10
11
12
# 元类实现
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]


class MyClass(metaclass=Singleton):

pass

2.The Factory Pattern 工厂模式

解决对象创建问题

工厂模式属于创建型模式, 它提供了一种创建对象的最佳方式.
在工厂模式中, 我们在创建对象时不会对客户端暴露创建逻辑, 并且时通过使用一个共同的接口来指向新创建的对象.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 根据品牌名生产不同的汽车

# bmw 生产线
class bmw:

def __str__(self):
return "我生产了一台BMW汽车"

# benz 生产线
class benz:

def __str__(self):
return "我生产了一台Benz汽车"

# 创建一个汽车工厂
class MachineFactory:

def build(self, brand):
if brand == "bmw":
machine = bmw()
print(machine)
elif brand == "benz":
machine = benz()
print(machine)


machineFactory = MachineFactory()

# 根据不同的品牌名生产不同的汽车
machineFactory.build("bmw")
machineFactory.build("benz")

3.The Builder Pattern 构造模式

控制复杂对象的构造

当对象需要多个部分组合起来一步步创建,并且创建和表示分离的时候。可以这么理解,你要买电脑,工厂模式直接返回一个你需要型号的电脑,但是构造模式允许你自定义电脑各种配置类型,组装完成后给你。这个过程你可以传入builder从而自定义创建的方式。

假如我们要生产一台Computer, 我们需要首先定义一个Computer类, 他表示了一个Computer由那些组件组成. 然后定义一个Builer, Builer用于组装Computer. 最后定义一个Enginner, 工程师告诉Builer用那些配件参数生产Computer, 然后得到一台根据具体参数生产的Computer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# 首先我们先定义一个 Computer 类
# 它表示一个 Computer 都由那些参数设备组成
class Computer:

def __init__(self, serialNumber):
self.serial = serialNumber
self.memory = None
self.ssd = None
self.gpu = None

def __str__(self):
info = """
Memory: {}GB
SSD : {}GB
Graphics Card: {}
""".format(
self.memory,
self.ssd,
self.gpu
)
info = "\n".join(list(filter(lambda x: x.strip(), info.split("\n"))))
return info


# 定义一个建造者, 用于构造一个 Computer
class ComputerBuilder:

def __init__(self):
self.computer = Computer("W540")

def setMemory(self, amount):
self.computer.memory = amount

def setSSD(self, amount):
self.computer.ssd = amount

def setGPU(self, amount):
self.computer.gpu = amount


# 定义一个工程师, 他告诉建造者该如何构造一个 Computer
class Engineer:

def __init__(self):
self.builder = None

def buildComputer(self, memory, ssd, gpu):
self.builder = ComputerBuilder()
self.builder.setMemory(memory)
self.builder.setSSD(ssd)
self.builder.setGPU(gpu)

@property
def computer(self):
return self.builder.computer


# 接下来我们创建一个 engineer 实例
enginner = Engineer()
# engineer 构造了一个 computer
enginner.buildComputer(
memory=32,
ssd=1024,
gpu="GeForce RTX 3090"
)
# 获得 computer
computer = enginner.computer
print(computer)

4.The Prototype Pattern 原型模式

解决对象拷贝的问题

可以使用Python内置的copy模块实现. 拷贝分为深拷贝和浅拷贝, 这里我觉得有点像C里面的指针. 浅拷贝相当于复制了对象的指针, 还是指向同一个对象, 而深拷贝则完全复制了一个新的对象.
深拷贝的优点是对象之间完全独立互不影响, 但是这个操作会比较消耗资源.
浅拷贝的优点是仅仅复制了指向对象的指针, 因为引用的都是同一个对象, 这个操作比深拷贝消耗的资源要少得多, 但是因为指向同一个对象, 所以当对象需要进行某些操作时候要慎重考虑.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import json
import copy


# 定义一本书
class Book:

def __init__(self, name, author, price, **kwargs):
self.name = name
self.author = author
self.price = price
self.__dict__.update(kwargs)

def __str__(self):
print(self.__dict__.keys())
attrNames = list(self.__dict__.keys())
attrs = dict()
for name in attrNames:
attrs.setdefault(name, getattr(self, name))
return json.dumps(attrs, indent=4)


class Prototype:

def __init__(self):
self.objects = {}

def register(self, identifier, obj):
self.objects[identifier] = obj

def unregister(self, identifiter):
del self.objects[identifiter]

def clone(self, identifier, **kwargs):
"""克隆一个对象, 即对象的深拷贝"""
obj = self.objects.get(identifier)
if not obj:
raise ValueError("Incorrect object identifier: {}".format(identifier))
newObj = copy.deepcopy(obj)
# 实现拷贝时自定义更新
newObj.__dict__.update(kwargs)
return newObj


if __name__ == '__main__':

b1 = Book(
name="Python程序设计",
author="闹闹",
price="99",
edition="1"
)

property = Prototype()
cid = "A123456789"
# 注册了一本新书
property.register(cid, b1)
# 克隆一个新对象
b2 = property.clone(cid, edition="2")

for i in (b1, b2):
print(i)
print("ID b1: {} b2: {}".format(id(b1), id(b2)))

5.The Adapter Pattern 适配器模式

解决接口不兼容问题

未完待续…

区别实例属性和类属性

类属性

这样定义的属性是类属性, 我们 new 两个实例测试下

1
2
3
4
5
6
7
8
9
10
11
class MyClass(object):

name: list = list()


if __name__ == '__main__':

m1 = MyClass()
m2 = MyClass()
print(id(m1.name))
print(id(m2.name))

可以看到指向了相同的地址

1
2
3
4
2078100290056
2078100290056

Process finished with exit code 0

实例属性

__init__ 方法中创建的属性是实例属性

1
2
3
4
5
6
7
8
9
10
11
12
class MyClass(object):

def __init__(self):
self.name: list = list()


if __name__ == '__main__':

m1 = MyClass()
m2 = MyClass()
print(id(m1.name))
print(id(m2.name))

可以看到指向了不同的地址

1
2
3
4
1631300614792
1631300614856

Process finished with exit code 0

总结

类属性属于类所有, 所有实例共享一个属性

实例属性属于实例所有, 每个实例各自独享一个属性

注意

不要对实例属性和类属性使用相同的名字,否则将产生难以发现的错误。

https://www.liaoxuefeng.com/wiki/1016959663602400/1017594591051072

查询重复记录

表名: table_name

查询列: column_name

单个条件

1
2
3
4
select * from table_name 
where column_name in(select column_name from table_name
group by column_name having count(column_name)>1)
order by column_name;

多个条件

1
2
3
4
5
6
7
8
9
10
select * from table_name as t1 
where
(
select count(*) from table_name t2
where
t2.column_name_1=t1.column_name_1 and
t2.column_name_2=t1.column_name_2 and
t2.column_name_3=t1.column_name_3 and
t2.column_name_4=t1.column_name_4
)>1;

删除重复只保留一个

表名: table_name

查询列: column_name

单个条件

1
2
3
delete from table_name 
where column_name in (select column_name from table_name group by column_name having count(column_name) > 1)
and ctid not in (select min(ctid) from table_name group by column_name having count(column_name)>1);

多个条件

1
2
3
4
5
6
7
8
9
delete from table_name 
where (column_name1,column_name2,column_name3) in
(select column_name1,column_name2,column_name3 from table_name
group by column_name1,column_name2,column_name3
having count(*) > 1)
and ctid not in
(select min(ctid) from table_name
group by column_name1,column_name2,column_name3
having count(*)>1);

https://blog.csdn.net/fm0517/article/details/61202099

查看日志

1
docker logs container_name_or_id

Docker 日志目录

1
/var/lib/docker/containers/container_id

设置Docker容器日志大小, 以docker-compose文件为例

1
2
3
4
5
6
7
v2ray: 
image: v2ray
restart: always
logging:
driver: "json-file"
options:
max-size: "5g"

日志被限制在5g大小.

更改全局设置

增加项文件

1
2
3
4
{
"log-driver":"json-file",
"log-opts": {"max-size":"500m", "max-file":"3"}
}

到文件, 如果没有则新建.

1
/etc/docker/daemon.json

重启docker

1
service docker restart

Your local changes to the following files would be overwritten by merge

错误描述

1
2
3
4
5
6
e66515c..389e67f  master     -> gitlab/master
error: Your local changes to the following files would be overwritten by merge:
config/clash/haikou.yaml
config/clash/yuncheng.yaml
Please commit your changes or stash them before you merge.
Aborting

方法一

放弃本地修改,直接覆盖

1
2
git reset --hard
git pull