---
title: 【CodiMD】安裝踩雷筆記...
date: 2021-01-26
is_modified: true
disqus: cynthiahackmd
categories:
- "資訊科技 › 開發與輔助工具"
tags:
- "Linux/Unix"
- "HackMD/CodiMD/HedgeDoc"
- "協同合作工具"
- "工具安裝與部署"
---
{%hackmd @CynthiaChuang/Github-Page-Theme %}
<br>
說實話我還是搞不懂為何需要建立 CodiMD,不過上面說要建那就來建吧~!
<!--more-->
## 先來聊聊 HackMD 與 CodiMD
<p class="illustration">
<img src="https://i.imgur.com/lobcWpo.png" alt="HackMD">
HackMD 官網截圖 (圖片來源: <a href="https://hackmd.io/"> HackMD 官網</a>)
</p>
之前提過 [HackMD](https://hackmd.io/) 是我用過最順手 Markdown 的文字編輯器。而 [CodiMD](https://demo.codimd.org) 其實就是 Open Source 的 HackMD Community Edition。
CodiMD 之前好像叫做 HackMD CE ,但為了避免命名混搖的困擾,因此中間修改過專案名稱(看 [這裡](https://github.com/hackmdio/codimd/issues/1170) 與 [這裡](https://github.com/hackmdio/codimd/issues/720)),由 HackMD CE 改成了 CodiMD。
不過,但說實話還是很混亂,而且是讓人更加的困惑!除了在一些文件與專案兩個名字會輪流出現外,還有另外一個讓人更困惑的是,名為 CodiMD 的 repository 其實是有兩個的,分別由 HackMD EE 與社群所維護的。
### 程式碼
由於上述原因它的程式碼是有兩個 repository。
1. **HackMD EE 維護**
- Source code:[hackmdio/codimd](https://github.com/hackmdio/codimd)
- Container: [hackmdio/docker-hackmd](https://github.com/hackmdio/docker-hackmd) / [Docker Deployment](https://hackmd.io/c/codimd-documentation/%2Fs%2Fcodimd-docker-deployment)
<br>
2. **社群維護**
- Source code:[codimd/server](https://github.com/codimd/server)
- Container: [codimd/container](https://github.com/codimd/container)
## 安裝步驟
這邊安裝了社群維護 CodiMD:
```shell=
$ git clone https://github.com/codimd/container.git codimd-container
$ cd codimd-container
$ docker-compose up
```
文件上寫的安裝指令相當簡單只有 3 條指令,執行完後,畫面上會出現 `HTTP Server listening at port 3000`,此時就算啟動完成了。
但是事情通常都是沒有這麼簡單的,我有那一次安裝環境照著指令輸完就過的?每次都會踩到一堆坑 QAQ
### 問題1:docker-compose 安裝
一開始的問題是因為我沒有裝過 **docker-compose**,因此一開始會出現未安裝的提示,所以照著 Ubuntu 的提示安裝了 **docker-compose**
```shell=
$ sudo apt install docker-compose
```
<br>原本以為這樣就安裝完成了,但重新執行時跳出了下面的 Error
> ERROR: Version in “./docker-compose.yml” is unsupported. You might be seeing this error because you’re using the wrong Compose file version. Either specify a version of “2” (or “2.0”) and place your service definitions under the `services` key, or omit the `version` key and place your service definitions at the root of the file to use version 1.
For more on the Compose file format versions, see [https://docs.docker.com/compose/compose-file/](https://docs.docker.com/compose/compose-file/)
<br>查了一下,根據 [issue #58](https://github.com/10up/wp-local-docker/issues/58#issuecomment-337963951) 的 commit,發現與docker-compose 版號有關:
> docker-compose v3 syntax is not supported by docker-compose until version 1.10.0. You’ll need to update docker-compose to a newer version to get rid of that error. Current version is 1.16.1
<br><br>果然下了 `docker-compose --version` 後,發現的版號只有 **1.8.0**,所以現在有兩個選擇:
1. 修改 docker-compose.yml 的版號,由 version: '3' 降成 version: '2'。
2. 是升級 docker-compose 版本。
<br>但查下目前 docker-compose [版本](https://github.com/docker/compose/tags) 已經來到 1.25.0-rc1,版本差的有點多,還是升級一下好了。
```shell=
$ sudo curl -L https://github.com/docker/compose/releases/download/1.25.0-rc1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose --version
```
<br>在執行 `docker-compose --version` 時 ,可能會遇到 `/usr/bin/docker-compose: 沒有此一檔案或目錄`,可以直接把先直接把檔案從 /usr/local/bin 搬到 /usr/bin,不然就是就是建立連結指令:
```shell=
$ sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
```
<br>再次查詢版號,此時就會顯示正確版號了,到這邊 docker-compose 算是安裝完成。
```shell=
$ docker-compose --version
docker-compose version 1.25.0-rc1, build 8552e8e2
```
### 問題2: could not find an available, non-overlapping IPv4 address
不過 docker-compose 安裝完,我還是不能跑 Orz ,這次換成
```shell
ERROR: could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network
```
<br>根據大家的[踩雷心得](https://stackoverflow.com/questions/43720339/docker-error-could-not-find-an-available-non-overlapping-ipv4-address-pool-am)(誤),大抵可分成三種狀況:
1. openvpn 執行中 running,這個狀況下
```shell=
$ service openvpn stop
```
2. docker network 滿了,則下
```shell=
$ docker network prune
```
3. 前兩條搞不定就試試看重起網路
```shell=
$ sudo service network-manager restart
```
<br>我自己是屬於第三種狀況,重起網路就 OK 了,但我同事還是不行。不過他後來發現 disable 掉某張網卡就行了,懷疑是與那張網卡的網段衝到了,因此他根據[這篇](http://www.itmuch.com/docker/24-docker-compose-network/),建立一個網路然後在 yaml 中設定名稱。
```shell=
networks:
# Internal network for communication with PostgreSQL/MySQL
backend:
ipam:
config:
- subnet: 172.20.0.0/16
```
到此我終於起起來了!!!!。:.゚ヽ(*´∀\`)ノ゚.:。
## 維護
### 備份與還原
若要執行備份指令的,直接下
```shell=
$ docker-compose exec database pg_dump hackmd -U hackmd > backup.sql
```
<br>根據 README 文件,而若要還原資料則是下:
```shell=
$ cat backup.sql | docker exec -i $(docker-compose ps -q database) psql -U hackmd
```
<br> 但我在還原資料時,直接得到一個 error
```shell=
SET
SET
SET
SET
CREATE EXTENSION
COMMENT
ALTER TYPE
ERROR: type "enum_Notes_permission" already exists
SET
SET
ERROR: relation "Authors" already exists
ALTER TABLE
ERROR: relation "Authors_id_seq" already exists
ALTER TABLE
ALTER SEQUENCE
ERROR: relation "Notes" already exists
ALTER TABLE
ERROR: relation "Revisions" already exists
ALTER TABLE
ERROR: relation "SequelizeMeta" already exists
ALTER TABLE
ERROR: relation "Sessions" already exists
ALTER TABLE
ERROR: relation "Temp" already exists
ALTER TABLE
ERROR: relation "Temps" already exists
ALTER TABLE
ERROR: relation "Users" already exists
ALTER TABLE
ALTER TABLE
ERROR: duplicate key value violates unique constraint "Authors_pkey"
DETAIL: Key (id)=(1) already exists.
CONTEXT: COPY Authors, line 1
setval
--------
2
(1 row)
ERROR: duplicate key value violates unique constraint "Notes_pkey"
DETAIL: Key (id)=(139cc586-bbe4-4e08-87b5-c77dab9c2d67) already exists.
CONTEXT: COPY Notes, line 1
ERROR: duplicate key value violates unique constraint "Revisions_pkey"
DETAIL: Key (id)=(d3a30eb1-24b1-4bd2-a08d-0b79a17b0d7e) already exists.
CONTEXT: COPY Revisions, line 1
ERROR: duplicate key value violates unique constraint "SequelizeMeta_pkey"
DETAIL: Key (name)=(20150504155329-create-users.js) already exists.
CONTEXT: COPY SequelizeMeta, line 1
ERROR: duplicate key value violates unique constraint "Sessions_pkey"
DETAIL: Key (sid)=(YU3T4MbAOIL0zoKwI1SWUphyroxHm0PS) already exists.
CONTEXT: COPY Sessions, line 1
COPY 0
COPY 0
ERROR: duplicate key value violates unique constraint "Users_pkey"
DETAIL: Key (id)=(8758f908-b87f-4376-aaff-507a16ba73ff) already exists.
CONTEXT: COPY Users, line 1
ERROR: multiple primary keys for table "Authors" are not allowed
ERROR: multiple primary keys for table "Notes" are not allowed
ERROR: multiple primary keys for table "Revisions" are not allowed
ERROR: multiple primary keys for table "SequelizeMeta" are not allowed
ERROR: multiple primary keys for table "Sessions" are not allowed
ERROR: multiple primary keys for table "Temp" are not allowed
ERROR: multiple primary keys for table "Temps" are not allowed
ERROR: multiple primary keys for table "Users" are not allowed
ERROR: relation "Users_profileid_key" already exists
ERROR: relation "authors_note_id_user_id" already exists
ERROR: relation "notes_alias" already exists
ERROR: relation "notes_shortid" already exists
```
<br><br>[問了一下](https://community.codimd.org/t/i-got-a-error-when-i-restored/42),才知道不能在 CodiMD 執行時恢復資料庫...,想想也合理,我為啥會在運行去恢復資料庫阿,白痴...。還好管理者沒有嫌棄我(反正他嫌棄了我也看不到),還很熱心的告訴我還原的詳細步驟:
1. 先停止所有服務,下 `docker-compose down` 或 `docker-compose down -v`,-v 會直接刪除 database。
2. 接下來單獨運行 database container,`docker-compose up -d database`。
3. 隨後執行 `cat backup.sql | docker-compose exec database psql -U hackmd`,從備份中還原。
4. 完成後,重新運行服務 `docker-compose up -d` 。
不過這恢復步驟有個前提就是: **nothing meaningful in the database yet**。
<br>如果是用預設那份 yml 檔,mount 的那個資料夾應該會對應到 **/var/lib/docker/volumes/codimd-container_database**,原本想說能不能用 `docker volume create`,並複製資料裡面的東西到新的 volume 中,事實證明可以,但不確定這樣的複製方法與文件的備份方法差了多少資料。
需要注意的是,在複製 volume 必須確保 database 已經停止,不然資料可能會不一致,因此管理者還是推薦用文件的備份方法 。
### 軟體升級
```shell=
$ cd codimd-container ## enter the directory
$ git pull ## pull new commits
$ docker-compose pull ## pull new containers
$ docker-compose up ## turn on
```
升級看來還滿簡單,不過因為 yml 檔與 config.json 有做了點客製化,所以沒有打算直接從 repository git pull 下來,我是直接換掉目前 yml 檔中 CodiMD 的 image 來源,取代 git pull 的步驟。
<br>不過重新 `docker-compose up` 時遇到了點小問題
```shell=
2019-06-04T06:16:56.142Z error: uncaughtException: HSTS must be passed a numeric maxAge parameter.
TypeError: HSTS must be passed a numeric maxAge parameter.
at Function.hsts (/codimd/node_modules/hsts/index.js:27:11)
at Object.<anonymous> (/codimd/app.js:85:18)
at Module._compile (module.js:653:30)
at Object.Module._extensions..js (module.js:664:10)
at Module.load (module.js:566:32)
at tryModuleLoad (module.js:506:12)
at Function.Module._load (module.js:498:3)
at Function.Module.runMain (module.js:694:10)
at startup (bootstrap_node.js:204:16)
at bootstrap_node.js:625:3
```
問題不大,直接照 [issue](https://github.com/hackmdio/codimd/issues/1159) 所說的,修改 config.json 即可。
### 使用者管理
超蠢的一件事,我剛註冊完帳號回頭就忘了我自己的密碼,偏偏 UI 上又沒有忘記密碼的選項 Orz,只好去[問問](https://github.com/codimd/container/issues/34),還好一條指令就搞定了。
```bash=
$ docker-compose exec codimd ./bin/manage_users --reset <mail address>
```
### 環境配置
CodiMD 環境配置有兩種方法一是配置 [Environment variables](https://github.com/codimd/server/blob/master/docs/configuration-env-vars.md),或是使用 [Config file](https://github.com/codimd/server/blob/master/docs/configuration-config-file.md)
## 小記
HackMD / CodiMD 是真的很好用,但說實話建置說明文件偏少(還是我太弱了!?),建置上相當的不方便。但管理者相當的熱心,回覆都還滿熱心且迅速的,如果有問題可以直接到 [論壇](https://community.codimd.org/) 提問。
## 參考資料
1. [CodiMD Documentation|HackMD](https://hackmd.io/c/codimd-documentation/%2Fs%2Fcodimd-documentation)
2. [建立個人用的 Markdown 筆記只要幾分鐘,使用 VirtualBox + Docker + HackMd (CodiMd)|TerryL](https://terryl.in/zh/private-markdown-note-by-vagrant-docker-hackmd/)
3. [How To Install Docker Compose on Ubuntu 16.04|DigitalOcean](https://www.digitalocean.com/community/tutorials/how-to-install-docker-compose-on-ubuntu-16-04)
4. [Docker “ERROR: could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network”|Stack Overflow](https://stackoverflow.com/questions/43720339/docker-error-could-not-find-an-available-non-overlapping-ipv4-address-pool-am)
5. [Docker系列教程24-Docker Compose网络设置|周立的博客 关注Spring Cloud、Docker](http://www.itmuch.com/docker/24-docker-compose-network/)
## 更新紀錄
:::spoiler 最後更新日期:2021-01-26
- 2021-01-26 更新:repository 資訊
- 2019-06-04 發布
:::
<br><br>
> **本文作者**: 辛西亞.Cynthia
> **本文連結**: [辛西亞的技能樹](https://cynthiachuang.github.io/How-to-Setup-CodiMD) / [hackmd 版本](https://hackmd.io/@CynthiaChuang/How-to-Setup-CodiMD)
> **版權聲明**: 部落格中所有文章,均採用 [姓名標示-非商業性-相同方式分享 4.0 國際](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en) (CC BY-NC-SA 4.0) 許可協議。轉載請標明作者、連結與出處!