Bài đăng nổi bật

Hướng dẫn thay đổi thư mục root mặc định của Docker trên Linux

Hoàn cảnh: người viết gặp một trường hợp như này Được team hạ tầng cấp cho một máy chủ gồm 2 phân vùng lưu trữ, 1 phân vùng 20GB được gắn và...

25 tháng 8, 2019

How to cache images in javascript

Ok, let me show my case:
I have a request that they need to apply parallax (like a anime action) to their website with about 20 images. What they want is loading all images and displaying to their customers.
But loading all images is a huge problem and if applying parallax, each frame must be reloaded that means every time user scrolls mouse we must reload image from server.
How do I solve this problem?
Let start with this script. This script will do:

  • Load images from server.
  • Apply ScrollMagic

<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js" integrity="sha256-lPE3wjN2a7ABWHbGz7+MKBJaykyzqCbU96BJWjio86U=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/ScrollMagic.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.7/plugins/animation.gsap.min.js" integrity="sha256-+9YNuItWuR4sbqeaNiJOxG0BvptYz4fbUXbIZoH5Jwo=" crossorigin="anonymous"></script>
</head>
<body>
<form class="move">
<fieldset>
<legend>Toggle duration</legend>
<div>
<input type="radio" name="duration" id="bound" value="300" checked="">
<label for="bound">bound to scrollbar (duration = 300)</label>
</div>
<div>
<input type="radio" name="duration" id="unbound" value="0">
<label for="unbound">unbound from scrollbar (duration = 0)</label>
</div>
</fieldset>
</form>
<div class="spacer s2"></div>
<div class="spacer s0" id="trigger"></div>
<div id="imagesequence">
<img id="myimg" src="assets/1.jpg"><br>
<a href="#" class="viewsource">view source</a>
</div>
<div class="spacer s2"></div>
<script>
// define images
var images = [
"assets/2.jpg",
"assets/3.jpg",
"assets/4.jpg",
"assets/5.jpg",
"assets/6.jpg",
"assets/7.jpg",
"assets/8.jpg",
"assets/9.jpg",
"assets/10.jpg",
"assets/11.jpg",
"assets/12.jpg",
"assets/13.jpg",
"assets/14.jpg",
"assets/15.jpg",
"assets/16.jpg",
"assets/17.jpg",
];
// TweenMax can tween any property of any object. We use this object to cycle through the array
var obj = {curImg: 0};
// create tween
var tween = TweenMax.to(obj, 0.5,
{
curImg: images.length - 1,  // animate propery curImg to number of images
roundProps: "curImg",               // only integers so it can be used as an array index
repeat: 3,                                  // repeat 3 times
immediateRender: true,          // load first image automatically
ease: Linear.easeNone,          // show every image the same ammount of time
onUpdate: function () {
console.log(obj.curImg);
$("#myimg").attr("src", images[obj.curImg]); // set the image source
}
}
);
// init controller
var controller = new ScrollMagic.Controller();
// build scene
var scene = new ScrollMagic.Scene({triggerElement: "#trigger", duration: 1000})
.setTween(tween)
// .addIndicators() // add indicators (requires plugin)
.addTo(controller);
// handle form change
$("form.move input[name=duration]:radio").change(function () {
scene.duration($(this).val());
});
</script>
</body>
</html>


If you turn on developer mode of your browser, you will see that each time you scroll your mouse, your browser will reload image from server event you've loaded it before. It's not good with a slow network.To solve this problem, I'll preload all images and cache it to browser's memory with this script:

function preloadImgs(url, callback){
var xhr = new XMLHttpRequest();
xhr.onload = function(){
var reader = new FileReader();
reader.onloadend = function(){
callback(reader.result);
};
reader.readAsDataURL(xhr.response);
};
xhr.open("GET", url);
xhr.responseType = "blob";
xhr.send();
}

And apply it by:

var imageCache = [];
var obj = null;
var tween = null;
var controller = null;
var scene = null;
var lock = 0;
for(var i = 0; i < images.length; i++){
preloadImgs(images[i], function(dataUrl){
imageCache.push(dataUrl);
if(imageCache.length === 16 && lock === 0){
obj = {curImg: 0};
tween = TweenMax.to(obj, 0.5,
{
curImg: imageCache.length - 1,
roundProps: "curImg",
repeat: 1,
immediateRender: true,
ease: Linear.easeNone,
onUpdate: function(){
console.log(obj.curImg);
$("#myImg").attr("src", imageCache[obj.curImg]);
}
});
controller = new ScrollMagic.Controller();
scene = new ScrollMagic.Scene({
triggerElement: "#trigger",
duration: 1000
})
.setTween(tween)
// .addIndicators()
.addTo(controller);
lock = 1;
}
});
}

You'll see that I've changed from directly using images array to Parallax library, I've used imageCache. In imageCache array, I've saved images in base64 format (You can see it in here)
Remember:

  • Because of using memory to cache images, you should decrease your images' size. In my example, if each image's size is 1MB, you must use at least 17MB memory to save.

  • When you begin access this page, you must wait until all images are loaded.
  • I try to use lock to know when all images are loaded.

21 tháng 2, 2019

Hướng dẫn build docker trên Ubuntu


Hướng dẫn build docker trên Ubuntu

Lưu ý: các lệnh trong bài viết này đều phải chạy với quyền sudo

1.Cài đặt docker

Để cài đặt docker, chạy lệnh sau:
sudo apt-get  docker.io
Để kiểm tra xem đã cài đặt được chưa thì chạy lệnh:
docker --version
Đưa docker trở thành một dịch vu của hệ thống:
sysemctl start docker
systemctl enable docker 

2. Giới thiệu một số lệnh docker thông dụng

Docker sử dụng một file có tên là dockerfile để tạo image. File này sẽ bao gồm một loạt các lệnh chỉ dẫn cho docker biết cách tạo image như thế nào.
Nguyên tắc đọc file này như sau:
  • Đọc lần lượt từ trên xuống dưới.
  • Mỗi dòng là một lệnh, để ngắt dòng cần dùng ký tự "\"
  • Nếu có sửa file này, docker sẽ bắt đầu lại từ dòng được sửa cho tới hết file.
Dưới đây là một số lệnh thường dùng (lưu ý viết hoa):
  • FROM: Tên image gốc được sử  dụng để tạo image này. Dòng này là dòng bắt buộc và phải nằm trên cùng của file dockerfile.
  • MAINTAINER: tùy chọn, ghi thông tin người tạo image.
  • RUN: là dòng lệnh sẽ được chạy trong quá trình build image.
  • ADD: thêm một file/thư mục từ host vào image, có một tùy chọn cho phép docker download file này từ một địa chỉ url.
  • COPY: tương tự như ADD nhưng không hỗ trợ giải nén file nén và không hỗ trợ  download từ url.
  • ENV: định nghĩa một biến môi trường.
  • CMD: lệnh trong image sẽ được chạy khi image được khởi động.
  • ENTRYPOINT: định nghĩa một dòng lệnh mặc định sẽ được chạy khi image được chạy.
  • WORKDIR: thư mục mà lệnh trong tùy chọn CMD sẽ chạy sau khi image khởi động xong.
  • USER: là tên user hoặc uuid của user sẽ được tạo để chạy trong môi trường của image.
  • VOLUME: cho phép image được truy cập một thư mục của host khi image chạy.
  • #: comment trong docker file.

3. Hướng dẫn build docker image cơ bản

Tạo một docker file bằng lệnh:
nano ./Dockerfile
Thêm dòng sau vào đầu file để build image từ base ubuntu:16.04
#Download base image ubuntu 16.04
FROM ubuntu:16.04
Thêm dòng sau để image có repository được cập nhật lúc build:
RUN apt-get update 
Thêm dòng sau để cài một số ứng dụng cần thiết, ở đây ta đang cài nginx, php-fpm:
RUN apt-get install -y nginx php7.0-fpm supervisor && \
    rm -rf /var/lib/apt/lists/*
Thêm dòng sau để thay virtualhost configure mặc định:
#Define the ENV variable
ENV nginx_vhost /etc/nginx/sites-available/default
ENV php_conf /etc/php/7.0/fpm/php.ini
ENV nginx_conf /etc/nginx/nginx.conf
ENV supervisor_conf /etc/supervisor/supervisord.conf
# Enable php-fpm on nginx virtualhost configuration
COPY default ${nginx_vhost}
RUN sed -i -e 's/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/g' ${php_conf} && \
    echo "\ndaemon off;" >> ${nginx_conf}
#Copy supervisor configuration
COPY supervisord.conf ${supervisor_conf}
Thêm dòng sau để tạo thư mục mới:
RUN mkdir -p /run/php && \
    chown -R www-data:www-data /var/www/html && \
    chown -R www-data:www-data /run/php
Thêm dòng sau để gắn thêm volume của host vào docker image:
# Volume configuration
VOLUME ["/etc/nginx/sites-enabled", "/etc/nginx/certs", "/etc/nginx/conf.d", "/var/log/nginx", "/var/www/html"]
Thêm dòng sau để các dịch vụ tự chạy sau khi image được khởi động xong:

# Configure Services and Port

COPY start.sh /start.sh

CMD ["./start.sh"]


EXPOSE 80 443
Để bắt đầu build image, ta chạy lệnh sau:
docker build -t nginx_image .
Lệnh trên sẽ tạo file image tại cùng thư mục với file dockerfile.
Sau khi build xong, có thể kiểm tra xem image đã được tạo thành công chưa bằng lênh, nếu thành công ta sẽ  thấy một image có tên là nginx_image hiện ra trong danh sách:
docker image
Để chạy image mới ta có thể dùng lệnh:
docker run -d -v /webroot:/var/www/html -p 80:80 --name hakase nginx_image
Có thể kiểm tra xem image đã khởi động xong chưa bằng lệnh:
docker ps

13 tháng 2, 2019

Sử dụng phân vùng swap trên môi trường Linux

1. Trước tiên cần hiểu SWAP trên môi trường Linux là gì?
Có thể hiểu đơn giản phân vùng SWAP là  một vùng nhớ bổ sung thêm cho bộ nhớ của hệ thống (RAM), nằm trên ổ đĩa cứng. Nếu bộ nhớ hệ thống bị đầy thì một số vùng nhớ sẽ được đưa xuống SWAP thay vì bị hệ thống hủy tiến trình.
Tuy nhiên, phân vùng SWAP có một vấn đề là do nó là một phần bộ nhớ nằm trên ổ đĩa (HDD hoặc SDD) nên tốc độ của nó sẽ chậm hơn so với tốc độ bộ nhớ chính nên không có nghĩa là bạn có thể sử dụng nó để thay thế hoàn toàn cho bộ nhớ chính.
2. Vậy nguyên tắc hoạt động của phân vùng SWAP như nào?
Có một hiểu lầm phổ biến về việc sử dụng phân vùng SWAP trên các hệ thống, đó là: việc sử dụng phân vùng SWAP gây ảnh hưởng tới hiệu năng của toàn bộ hệ thống do tốc độ đọc ghi trên phân vùng này chậm hơn tốc độ đọc ghi trên RAM. Điều này là hoàn toàn sai lầm. Trong trường hợp hệ thống của bạn có đủ RAM để hoạt động, việc bạn có cấp thêm phân vùng SWAP cho hệ thống hay không cũng không ảnh hưởng gì tới hiệu năng của hệ thống do hệ thống không phải liên tục chuyển đổi giữa RAM và SWAP. Còn trong trường hợp bạn không có đủ RAM thì sao?  Như các bạn đã biết thì bộ nhớ RAM có giá thành cao hơn rất nhiều so với giá của ổ đĩa và rõ ràng là bạn không thể cứ tăng RAM lên liên tục cho hệ thống, khi đó phân vùng SWAP sẽ giải quyết bài toán này cho bạn. Hãy xem ví dụ dưới đây:
  • Nếu bạn không sử dụng phân vùng SWAP và khi RAM của bạn bị sử dụng hết, kernel của hệ thống sẽ lựa chọn một/nhiều tiến trình mà nó nghĩ là cần phải loại bỏ (việc lựa chọn như nào phụ thuộc vào thuật toán được trang bị cho kernel) và loại bỏ chúng (kill).
  • Nếu bạn sử dụng phân vùng SWAP thì khi RAM của bạn bị sử dụng hết, kernel của hệ thống sẽ lựa chọn một vùng nhớ (memory page) ít được sử dụng nhất để đẩy xuống phân vùng SWAP để giải phóng RAM sử dụng vào các mục đích khác. Việc này có thể làm chậm hệ thống một chút nhưng sẽ đảm bảo cho ứng dụng của bạn không bị ảnh hưởng bới những ứng dụng khác.

Tuy nhiên, bạn cần luôn nhớ trong trường hợp nếu bạn có phân vùng SWAP mà vẫn bị hết thì tiến trình sẽ vẫn bị loại bỏ bởi kernel.
3. Vậy câu hỏi đặt ra ở đây là liệu có thực sự cần phân vùng SWAP?
Câu trả lời ở đây chính xác là TỐT NHẤT BẠN NÊN SỬ DỤNG, bởi lý do tôi đã nêu ở trên: nếu bạn đủ RAM thì hệ thống không phải thường xuyên đổ vùng nhớ xuống SWAP nên sẽ không bị ảnh hưởng tới hiệu năng hệ thống, còn trong trường hợp bị thiếu RAM (điều mà bạn không biết chắc lúc nào sẽ xảy ra) thì SWAP sẽ giúp cho các ứng dụng của bạn không bị ảnh hưởng.
4. Vậy tạo phân vùng SWAP như nào?
Để tạo phân vùng SWAP bạn cần có quyền sudo trên hệ thống.
Dùng lệnh dd để tạo file swap trên thư mục gốc của hệ thống, trong đó bs là kích thước block (block size) và count là số block., trong ví dụ dưới đây là tạo một file swap 4GB
sudo dd if=/dev/zero of=/swapfile bs=1G count=4
Trong đó:
- bs và count: có thể là c = 1, w = 2, b = 512, kB = 1000, K = 1024,  MB = 1000 * 1000, M = 1024 * 1024, xM = M, GB = 1000 * 1000 * 1000, G = 1024 * 1024 * 1024 cứ như thế với T, P, E, Z và Y
Cập nhật quyền read, write cho file swap:
sudo chmod 600 /swapfile
Cài đặt phân vùng swap:
sudo mkswap /swapfile
Cho phép hệ thống sử dụng file swap này là vùng nhớ swap:
sudo swapon /swapfile
Kiểm tra xem đã làm đúng các thao tác chưa:
sudo swapon -s
Hoặc:
sudo swapon --show
Cho phép hệ thống sử dụng phân vùng swap vừa tạo ngay cả khi bị khởi động lại:
sudo vi /etc/fstab
Thêm vào dòng sau:

/swapfile swap swap defaults 0 0 
Kiểm tra lại xem fstab đã được chưa bằng lệnh:
mount -a
Nếu không có thông báo lỗi nào hiện ra thì đã thêm vào fstab thành công.
Tham khảo thêm tại:
https://linuxize.com/post/create-a-linux-swap-file/

27 tháng 1, 2019

Ý nghĩa các bản ghi DNS

1. Bản ghi A
Được sử dụng để gắn một domain với một địa chỉ IPv4 cụ thể theo cấu trúc name - value, trong đó name sẽ là hostname hoặc một subdomain.
Giá trị nhận vào là một IPv4.
Trên Amazon Route 53,  value có thể là một alias trỏ tới một tên miền khác.
2. Bản ghi AAAA
Có ý nghĩa tương tự như bản ghi A nhưng value là một địa chỉ IPv6
Giá trị nhận vào là một IPv6
3. Bản ghi CNAME
Là viết tắt của Canonical Name.
Bản ghi được sử dụng để trỏ một domain tới một domain khác.
Giá trị là một domain/subdomain.
Ví dụ: domain1.com --> domain2.com.
4. Bản ghi MX
Là bản ghi được sử dụng để trỏ tới các máy chủ mail.
5. Bản ghi NS
Là viết tắt của Name Server.
Là bản ghi chứa danh sách các Name Server (hoặc hiểu nôm na là các DNS server) được sử dụng để trả về các truy vấn tên miền.
Giá trị nhận vào là danh sách domain DNS
Ví dụ khi bạn truy vấn 1 tên miền sẽ thấy danh sách các server trả lời truy vấn như sau:
ns1.itahost.com
ns2.itahost.com
6. Bản ghi SOA
Là viết tắt của Server Of Authority.
Mọi domain bắt buộc phải có bản ghi này.
Cấu trúc của bản ghi này bao gồm:
https://www.techopedia.com/2/28806/internet/12-dns-records-explained
  • Địa chỉ Name Server chính của tên miền (thường là địa chỉ DNS)
  • Địa chỉ mail của người có trách nhiệm nếu gặp sự cố (Lưu ý, bản ghi SOA không chấp nhận @ nên địa chỉ này sẽ thay @ bằng dấu ".", admin@gmail.com sẽ thành admin.gmail.com)
  • Timestamp của lần cập nhật gần nhất.
  • Tần suất để làm mới nội dung bản ghi, tính bằng giây.
  • Số giây để hệ thống thử cập nhật lại nội dung bản ghi nếu việc làm mới bị lỗi.
  • Số giây tối đa để hệ thống coi một máy chủ gốc giữ nội dung bản ghi tham chiếu là lỗi.
  • Chỉ ra thời gian sống (TTL) tối đa mà một kết quả mà DNS trả về có hiệu lực, nếu quá thời điểm này, client cần truy vấn lại để lấy thông tin.
7.Bản ghi RP
Là viết tắt của Responsible Person.
Bản ghi này thường nằm trong bản ghi SOA, thường là địa chỉ email của người quản trị để liên hệ khi gặp sự cố.
8. Bản ghi SPF
Là viết tắt của Sender Policy Framework.
Bản ghi này được sử dụng để chỉ ra danh sách các máy chủ được phép gửi mail từ domain này.
9. Bản ghi TXT
Đây là một bản ghi tùy chọn, được sử dụng cho rất nhiều mục đích khác nhau. Ví dụ ta có thể dùng nội dung bản ghi này để xác thực chủ sở hữu tên miền,...
Xem thêm tại: